payza_payments 0.1.0

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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +135 -0
  7. data/Rakefile +1 -0
  8. data/lib/payza_payments.rb +23 -0
  9. data/lib/payza_payments/base.rb +17 -0
  10. data/lib/payza_payments/button_generator.rb +41 -0
  11. data/lib/payza_payments/ipn_handler.rb +44 -0
  12. data/lib/payza_payments/version.rb +3 -0
  13. data/payza_payments.gemspec +29 -0
  14. data/spec/payza_payments/button_generator_spec.rb +24 -0
  15. data/spec/spec_helper.rb +6 -0
  16. data/test/dummy/.gitignore +16 -0
  17. data/test/dummy/Gemfile +54 -0
  18. data/test/dummy/README.rdoc +28 -0
  19. data/test/dummy/Rakefile +6 -0
  20. data/test/dummy/app/assets/images/.keep +0 -0
  21. data/test/dummy/app/assets/javascripts/application.js +16 -0
  22. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  23. data/test/dummy/app/controllers/application_controller.rb +5 -0
  24. data/test/dummy/app/controllers/concerns/.keep +0 -0
  25. data/test/dummy/app/controllers/dummy_controller.rb +5 -0
  26. data/test/dummy/app/helpers/application_helper.rb +2 -0
  27. data/test/dummy/app/mailers/.keep +0 -0
  28. data/test/dummy/app/models/.keep +0 -0
  29. data/test/dummy/app/models/concerns/.keep +0 -0
  30. data/test/dummy/app/views/dummy/index.html.haml +1 -0
  31. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  32. data/test/dummy/bin/bundle +3 -0
  33. data/test/dummy/bin/rails +4 -0
  34. data/test/dummy/bin/rake +4 -0
  35. data/test/dummy/config.ru +4 -0
  36. data/test/dummy/config/application.rb +23 -0
  37. data/test/dummy/config/boot.rb +4 -0
  38. data/test/dummy/config/database.yml +25 -0
  39. data/test/dummy/config/environment.rb +5 -0
  40. data/test/dummy/config/environments/development.rb +29 -0
  41. data/test/dummy/config/environments/production.rb +80 -0
  42. data/test/dummy/config/environments/test.rb +36 -0
  43. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  44. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  45. data/test/dummy/config/initializers/inflections.rb +16 -0
  46. data/test/dummy/config/initializers/mime_types.rb +5 -0
  47. data/test/dummy/config/initializers/payza.rb +4 -0
  48. data/test/dummy/config/initializers/secret_token.rb +12 -0
  49. data/test/dummy/config/initializers/session_store.rb +3 -0
  50. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  51. data/test/dummy/config/locales/en.yml +23 -0
  52. data/test/dummy/config/payza.yml +14 -0
  53. data/test/dummy/config/routes.rb +58 -0
  54. data/test/dummy/db/schema.rb +16 -0
  55. data/test/dummy/db/seeds.rb +7 -0
  56. data/test/dummy/dump.rdb +0 -0
  57. data/test/dummy/lib/assets/.keep +0 -0
  58. data/test/dummy/lib/tasks/.keep +0 -0
  59. data/test/dummy/public/404.html +58 -0
  60. data/test/dummy/public/422.html +58 -0
  61. data/test/dummy/public/500.html +57 -0
  62. data/test/dummy/public/favicon.ico +0 -0
  63. data/test/dummy/public/robots.txt +5 -0
  64. data/test/dummy/spec/controllers/dummy_controller_spec.rb +43 -0
  65. data/test/dummy/spec/spec_helper.rb +43 -0
  66. data/test/dummy/vendor/assets/javascripts/.keep +0 -0
  67. data/test/dummy/vendor/assets/stylesheets/.keep +0 -0
  68. metadata +263 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3a2eb8ce7c8f9c67f7d01d9b96a3dd840d3c636f
4
+ data.tar.gz: 4f8d0ed3b043c50c59a7541ce54c04f7dd0036d3
5
+ SHA512:
6
+ metadata.gz: 05756a59ad447e1330d0abfc977407fce2e6f53cd08b8565ad3eeb2c75dcc11856dd4a8bf67f0f4de77cbdd3ac733775648579f688c7df243acf438c376e5407
7
+ data.tar.gz: f39a10e68a5684923f687260a2d9b2a94e787bae39ed212827f300a072dcc63d4112804e300b9f96166312066742311a12f547fd160b5fe18f2ea6425557b7a1
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea/
19
+ .DS_Store
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ before_script: cd ./test/dummy/ && bundle install
5
+ script: cd ./test/dummy/ && bundle exec rake spec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in payza_payments.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Patricio Cano
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # PayzaPayments
2
+ [![Build Status](https://travis-ci.org/FreedomVPN/liberty_reserve_payments.png?branch=master)](https://travis-ci.org/FreedomVPN/liberty_reserve_payments)
3
+
4
+ Configure buttons for Payza based on your requirements and validate IPN requests sent by Payza.
5
+ With this gem the user of your shop can pay for a digital item (or any type of item) and you can validate the transaction
6
+ after it was made.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'payza_payments'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install payza_payments
21
+
22
+ ## Usage
23
+
24
+ After the installation, you still need two files for the gem to work. A Yaml config file and an initializer.
25
+
26
+ ### config/payza.yml
27
+ ```yaml
28
+ development:
29
+ ipn_security_code: xhs123457
30
+ merchant_email: sample@example.com
31
+ sandbox: true
32
+
33
+ production:
34
+ ipn_security_code: xhs123457
35
+ merchant_email: sample@example.com
36
+ sandbox: false
37
+
38
+ test:
39
+ ipn_security_code: xhs123457
40
+ merchant_email: sample@example.com
41
+ sandbox: true
42
+ ```
43
+
44
+ ### config/initializers/payza.rb
45
+ ```ruby
46
+ require 'payza_payments'
47
+
48
+ PAYZA_CONFIG = YAML.load_file("#{Rails.root}/config/payza.yml")[Rails.env].symbolize_keys
49
+ ```
50
+
51
+ After creating these files you still need to add the methods provided by this gem to your PaymentsController.
52
+ To do this you can add the following template methods to you file:
53
+
54
+ ```ruby
55
+ def pay_item_with_payza
56
+ # With this you will pass the ButtonGenerator instance to the view
57
+ # in order to be able to get the button in your view with the correct
58
+ # parameters.
59
+ @payza = PayzaPayments::ButtonGenerator.new PAYZA_CONFIG
60
+ @invoice = Invoice.new(params[:invoice])
61
+ end
62
+ ```
63
+
64
+ There are two methods for generating buttons. `.generate_simple_button` and
65
+ `.generate_subscription_button`. Both take similar parameters:
66
+ ```ruby
67
+ # action points to the current view
68
+ # order_id can be any identifier you want. It should allow you to match
69
+ # the IPN request to something in your application.
70
+ .generate_simple_button(action, purchase_type, item_name, amount, currency,
71
+ return_url, cancel_url, item_description, order_id)
72
+
73
+ # time_unit: can be 'Day', 'Week', 'Month', 'Year'
74
+ # period_length: gives how long the subscription will be, depending on time_unit
75
+ # it can go from 1 to 90.
76
+ .generate_subscription_button(action, purchase_type, item_name, amount, currency,
77
+ return_url, cancel_url, item_description, order_id,
78
+ time_unit, period_length)
79
+ ```
80
+ The code in the view may look like this (Haml example)
81
+ ```haml
82
+ = @payza.generate_simple_button(self, :item, 'Sample item', 5, 'EUR', 'http://exa.co/success',
83
+ 'http://exa.co/cancel', 'Sample Desc', @invoice.id)
84
+
85
+ ```
86
+ You should also add a route for Payza to send the IPN notifications. This gem supports both v1 and v2
87
+ of Payza. PayzaPayments will only validate the basic verification parameters. After a successful validation
88
+ you should still manually go through the parameters in order to match the payment to a corresponding order.
89
+
90
+ It can point to a method looking like this:
91
+
92
+ ```ruby
93
+ def validate_ipn_v2
94
+ handler = PayzaPayments::IpnHandler.new PAYZA_CONFIG
95
+ response = handler.handle_ipn_v2(params[:token])
96
+ if response == 'INVALID REQUEST'
97
+ # Response is not valid, log it and review it later
98
+ else
99
+ # The transaction has been successfully verified
100
+ # use the response hash to validate it has the
101
+ # correct data. You should use response['apc_1'] to
102
+ # fetch the order id, or any other parameter you passed
103
+ # on the view to validate against your DB.
104
+ invoice = Invoice.find(response['apc_1'])
105
+ if (response['ap_merchant'] == handler.merchant_email and
106
+ response['ap_status'] == 'Success' and response['ap_amount'] == invoice.amount)
107
+ # Now we know that the transaction was successful, the amount matches and
108
+ # the payment was sent to us. For a list of all the IPN variables go to
109
+ # https://dev.payza.com/resources/references/ipn-variables
110
+ else
111
+ # Something devious has happened!
112
+ end
113
+ end
114
+ end
115
+
116
+ def validate_ipn
117
+ handler = ...
118
+ response = handler.handle_ipn(params)
119
+ if response == true
120
+ # params[:ap_securitycode] and params[:ap_merchant] have already been
121
+ # validated. You should still validate the rest.
122
+ else
123
+ # INVALID
124
+ end
125
+ end
126
+
127
+ ```
128
+
129
+ ## Contributing
130
+
131
+ 1. Fork it
132
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
133
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
134
+ 4. Push to the branch (`git push origin my-new-feature`)
135
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ require 'attr_required'
2
+ require 'attr_optional'
3
+ require 'payza_payments/version'
4
+ require 'payza_payments/base'
5
+ require 'payza_payments/ipn_handler'
6
+ require 'payza_payments/button_generator'
7
+
8
+ module PayzaPayments
9
+
10
+ def self.sandbox!
11
+ self.sandbox = true
12
+ end
13
+
14
+ def self.sandbox=(boolean)
15
+ @@sandbox = boolean
16
+ end
17
+
18
+ def self.sandbox?
19
+ @@sandbox
20
+ end
21
+ self.sandbox = false
22
+
23
+ end
@@ -0,0 +1,17 @@
1
+ module PayzaPayments
2
+ class Base
3
+ include AttrRequired, AttrOptional
4
+
5
+ attr_required :ipn_security_code, :merchant_email, :sandbox
6
+
7
+ def initialize(attributes = {})
8
+ if attributes.is_a?(Hash)
9
+ (required_attributes + optional_attributes).each do |key|
10
+ value = attributes[key]
11
+ self.send "#{key}=", value
12
+ end
13
+ end
14
+ attr_missing!
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ #require 'action_view'
2
+ module PayzaPayments
3
+ class ButtonGenerator < Base
4
+ include ActionView::Helpers
5
+
6
+ def initialize(attributes = {})
7
+ super
8
+ end
9
+
10
+ def generate_simple_button(action, purchase_type, item_name, amount, currency, return_url, cancel_url, item_description, order_id)
11
+ action.content_tag(:form, method: :post, action: 'https://secure.payza.com/checkout') do
12
+ common_tags(purchase_type, item_name, amount, currency, return_url, cancel_url, item_description, order_id)
13
+ end
14
+ end
15
+
16
+ def generate_subscription_button(action, purchase_type, item_name, amount, currency, return_url, cancel_url,
17
+ item_description, order_id, time_unit, period_length)
18
+ action.content_tag :form, method: :post, action: 'https://secure.payza.com/checkout' do
19
+ common_tags(purchase_type, item_name, amount, currency, return_url, cancel_url, item_description, order_id) +
20
+ tag(:input, type: :hidden, name: 'ap_timeunit', value: time_unit) +
21
+ tag(:input, type: :hidden, name: 'ap_periodlength', value: period_length)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def common_tags(purchase_type, item_name, amount, currency, return_url, cancel_url, item_description, order_id)
28
+ tag(:input, type: :hidden, name: 'ap_purchasetype', value: purchase_type) +
29
+ tag(:input, type: :hidden, name: 'ap_merchant', value: self.merchant_email) +
30
+ tag(:input, type: :hidden, name: 'ap_itemname', value: item_name) +
31
+ tag(:input, type: :hidden, name: 'ap_currency', value: currency) +
32
+ tag(:input, type: :hidden, name: 'ap_amount', value: amount) +
33
+ tag(:input, type: :hidden, name: 'ap_description', value: item_description) +
34
+ tag(:input, type: :hidden, name: 'ap_returnurl', value: return_url) +
35
+ tag(:input, type: :hidden, name: 'ap_cancelurl', value: cancel_url) +
36
+ tag(:input, type: :hidden, name: 'apc_1', value: order_id) +
37
+ tag(:input, type: :image, name: 'ap_image', src: 'https://www.payza.com/images/payza-buy-now.png')
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ require 'httparty'
2
+ module PayzaPayments
3
+ class IpnHandler < Base
4
+
5
+ SANDBOX_IPN = 'https://sandbox.payza.com/sandbox/ipn2.ashx'
6
+ PRODUCTION_IPN = 'https://secure.payza.com/ipn2.ashx'
7
+
8
+ def initialize(attributes = {})
9
+ super
10
+ end
11
+
12
+ def handle_ipn(params)
13
+ if params[:ap_securitycode] == self.ipn_security_code and params[:ap_merchant] == self.merchant_email
14
+ true
15
+ else
16
+ false
17
+ end
18
+ end
19
+
20
+ def handle_ipn_v2(token)
21
+ validate_ipn(token) ? @response.parsed_response : 'INVALID REQUEST'
22
+ end
23
+
24
+ private
25
+
26
+ def validate_ipn(token)
27
+ if self.sandbox?
28
+ send_ipn_validation(token, SANDBOX_IPN)
29
+ else
30
+ send_ipn_validation(token, PRODUCTION_IPN)
31
+ end
32
+ end
33
+
34
+ def send_ipn_validation(token_value, url)
35
+ token = { token: token_value }
36
+ @response = HTTParty.post(url, token)
37
+ if @response.parsed_response == 'INVALID TOKEN'
38
+ false
39
+ else
40
+ true
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module PayzaPayments
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'payza_payments/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'payza_payments'
8
+ spec.version = PayzaPayments::VERSION
9
+ spec.authors = ['Patricio Cano']
10
+ spec.email = %w(admin@insomniware.com)
11
+ spec.description = %q{Validate Payza IPN payments and create payment buttons}
12
+ spec.summary = %q{You can generate buy now and subscription buttons for your application, and then
13
+ validate the IPN request sent.}
14
+ spec.homepage = 'https://github.com/supernova32/payza_payments'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = %w(lib)
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.3'
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'rspec-rails'
26
+ spec.add_dependency 'attr_required', '>= 0.0.5'
27
+ spec.add_dependency 'httparty', '>=0.10.0'
28
+ spec.add_dependency 'rails', '>=3.2.14'
29
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'action_view'
3
+
4
+ class ButtonTest < ActionView::TestCase
5
+
6
+ end
7
+
8
+ describe PayzaPayments::ButtonGenerator do
9
+ let :attributes do
10
+ {ipn_security_code: 'U123456', merchant_email: 'support@freedomvpn.info', sandbox: true}
11
+ end
12
+
13
+ let :instance do
14
+ PayzaPayments::ButtonGenerator.new attributes
15
+ end
16
+
17
+ describe '.generate_simple_button' do
18
+
19
+ it 'should render a valid button' do
20
+ instance.generate_simple_button(ButtonTest.new, :item, 'test', 5, 'EUR', 'https://freedomvpn.info',
21
+ 'https://freedomvpn.info', 'test', 1).should == '<form action="https://secure.payza.com/checkout" method="post"><input name="ap_purchasetype" type="hidden" value="item" /><input name="ap_merchant" type="hidden" value="support@freedomvpn.info" /><input name="ap_itemname" type="hidden" value="test" /><input name="ap_currency" type="hidden" value="EUR" /><input name="ap_amount" type="hidden" value="5" /><input name="ap_description" type="hidden" value="test" /><input name="ap_returnurl" type="hidden" value="https://freedomvpn.info" /><input name="ap_cancelurl" type="hidden" value="https://freedomvpn.info" /><input name="apc_1" type="hidden" value="1" /><input name="ap_image" src="https://www.payza.com/images/payza-buy-now.png" type="image" /><input name="ap_timeunit" type="hidden" value="Month" /><input name="ap_periodlength" type="hidden" value="12" /></form>'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require 'payza_payments'
3
+ #require 'action_view/test_helper'
4
+ #RSpec.configure do |config|
5
+ # config.include ActionView::TestCase::Behavior
6
+ #end
@@ -0,0 +1,16 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+ /db/*.sqlite3-journal
13
+
14
+ # Ignore all logfiles and tempfiles.
15
+ /log/*.log
16
+ /tmp
@@ -0,0 +1,54 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
4
+ gem 'rails', '4.0.0'
5
+
6
+ # Use sqlite3 as the database for Active Record
7
+ gem 'sqlite3'
8
+
9
+ # Use SCSS for stylesheets
10
+ gem 'sass-rails', '~> 4.0.0'
11
+
12
+ # Use Uglifier as compressor for JavaScript assets
13
+ gem 'uglifier', '>= 1.3.0'
14
+
15
+ # Use CoffeeScript for .js.coffee assets and views
16
+ gem 'coffee-rails', '~> 4.0.0'
17
+
18
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
19
+ # gem 'therubyracer', platforms: :ruby
20
+
21
+ # Use jquery as the JavaScript library
22
+ gem 'jquery-rails'
23
+ gem 'better_errors'
24
+ gem 'binding_of_caller'
25
+ gem 'rspec-rails'
26
+ gem 'simplecov'
27
+ gem 'capybara'
28
+ gem 'shoulda-matchers'
29
+
30
+ # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
31
+ gem 'turbolinks'
32
+
33
+ gem 'payza_payments', git: 'git@github.com:supernova32/payza_payments.git'
34
+ gem 'haml-rails'
35
+
36
+ # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
37
+ gem 'jbuilder', '~> 1.2'
38
+
39
+ group :doc do
40
+ # bundle exec rake doc:rails generates the API under doc/api.
41
+ gem 'sdoc', require: false
42
+ end
43
+
44
+ # Use ActiveModel has_secure_password
45
+ # gem 'bcrypt-ruby', '~> 3.0.0'
46
+
47
+ # Use unicorn as the app server
48
+ # gem 'unicorn'
49
+
50
+ # Use Capistrano for deployment
51
+ # gem 'capistrano', group: :development
52
+
53
+ # Use debugger
54
+ # gem 'debugger', group: [:development, :test]