zarinpal 0.0.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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +24 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +1 -0
  9. data/doc/Zarinpal.html +338 -0
  10. data/doc/Zarinpal/Configuration.html +445 -0
  11. data/doc/Zarinpal/Errors.html +149 -0
  12. data/doc/Zarinpal/PaymentRequest.html +805 -0
  13. data/doc/Zarinpal/PaymentVerification.html +540 -0
  14. data/doc/Zarinpal/Response.html +669 -0
  15. data/doc/Zarinpal/Response/ResponseError.html +123 -0
  16. data/doc/_index.html +184 -0
  17. data/doc/class_list.html +54 -0
  18. data/doc/css/common.css +1 -0
  19. data/doc/css/full_list.css +57 -0
  20. data/doc/css/style.css +338 -0
  21. data/doc/doc/_index.html +88 -0
  22. data/doc/doc/class_list.html +54 -0
  23. data/doc/doc/css/common.css +1 -0
  24. data/doc/doc/css/full_list.css +57 -0
  25. data/doc/doc/css/style.css +338 -0
  26. data/doc/doc/file_list.html +53 -0
  27. data/doc/doc/frames.html +26 -0
  28. data/doc/doc/index.html +88 -0
  29. data/doc/doc/js/app.js +214 -0
  30. data/doc/doc/js/full_list.js +178 -0
  31. data/doc/doc/js/jquery.js +4 -0
  32. data/doc/doc/method_list.html +53 -0
  33. data/doc/doc/top-level-namespace.html +102 -0
  34. data/doc/file.README.html +105 -0
  35. data/doc/file_list.html +56 -0
  36. data/doc/frames.html +26 -0
  37. data/doc/index.html +105 -0
  38. data/doc/js/app.js +214 -0
  39. data/doc/js/full_list.js +178 -0
  40. data/doc/js/jquery.js +4 -0
  41. data/doc/method_list.html +191 -0
  42. data/doc/top-level-namespace.html +112 -0
  43. data/lib/zarinpal.rb +37 -0
  44. data/lib/zarinpal/errors.rb +17 -0
  45. data/lib/zarinpal/payment_request.rb +44 -0
  46. data/lib/zarinpal/payment_verification.rb +34 -0
  47. data/lib/zarinpal/response.rb +50 -0
  48. data/lib/zarinpal/version.rb +3 -0
  49. data/spec/lib/configuration_spec.rb +18 -0
  50. data/spec/lib/errors_spec.rb +7 -0
  51. data/spec/lib/payment_request_spec.rb +40 -0
  52. data/spec/lib/payment_verification_spec.rb +41 -0
  53. data/spec/lib/response_spec.rb +46 -0
  54. data/spec/lib/version_spec.rb +7 -0
  55. data/spec/spec_helper.rb +20 -0
  56. data/zarinpal.gemspec +29 -0
  57. metadata +206 -0
@@ -0,0 +1,112 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <title>
7
+ Top Level Namespace
8
+
9
+ &mdash; Documentation by YARD 0.8.7.2
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ hasFrames = window.top.frames.main ? true : false;
19
+ relpath = '';
20
+ framesUrl = "frames.html#!" + escape(window.location.href);
21
+ </script>
22
+
23
+
24
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
25
+
26
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
27
+
28
+
29
+ </head>
30
+ <body>
31
+ <div id="header">
32
+ <div id="menu">
33
+
34
+ <a href="_index.html">Index</a> &raquo;
35
+
36
+
37
+ <span class="title">Top Level Namespace</span>
38
+
39
+
40
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
41
+ </div>
42
+
43
+ <div id="search">
44
+
45
+ <a class="full_list_link" id="class_list_link"
46
+ href="class_list.html">
47
+ Class List
48
+ </a>
49
+
50
+ <a class="full_list_link" id="method_list_link"
51
+ href="method_list.html">
52
+ Method List
53
+ </a>
54
+
55
+ <a class="full_list_link" id="file_list_link"
56
+ href="file_list.html">
57
+ File List
58
+ </a>
59
+
60
+ </div>
61
+ <div class="clear"></div>
62
+ </div>
63
+
64
+ <iframe id="search_frame"></iframe>
65
+
66
+ <div id="content"><h1>Top Level Namespace
67
+
68
+
69
+
70
+ </h1>
71
+
72
+ <dl class="box">
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+ </dl>
82
+ <div class="clear"></div>
83
+
84
+ <h2>Defined Under Namespace</h2>
85
+ <p class="children">
86
+
87
+
88
+ <strong class="modules">Modules:</strong> <span class='object_link'><a href="Zarinpal.html" title="Zarinpal (module)">Zarinpal</a></span>
89
+
90
+
91
+
92
+
93
+ </p>
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+ </div>
104
+
105
+ <div id="footer">
106
+ Generated on Sat Mar 1 21:03:58 2014 by
107
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
+ 0.8.7.2 (ruby-2.1.0).
109
+ </div>
110
+
111
+ </body>
112
+ </html>
@@ -0,0 +1,37 @@
1
+ require 'zarinpal/version'
2
+ require 'zarinpal/payment_request'
3
+ require 'zarinpal/response'
4
+ require 'zarinpal/payment_verification'
5
+ require 'zarinpal/errors'
6
+
7
+ # A library to send and verify transactions with Zaripal
8
+ #
9
+ # @see http://zarinpal.com/
10
+ # @author {http://github.com/arashm Arash Mousavi}
11
+ module Zarinpal
12
+ class << self
13
+ attr_accessor :configuration
14
+ end
15
+
16
+ def self.configure
17
+ self.configuration ||= Configuration.new
18
+ yield configuration
19
+ end
20
+
21
+ # Configures the gem
22
+ #
23
+ # @example
24
+ # Zarinpal.configure do |config|
25
+ # config.merchant_id = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
26
+ # config.callback_url = 'http://example.com/call_back'
27
+ # config.client = 'https://de.zarinpal.com/pg/services/WebGate/wsdl'
28
+ # end
29
+ class Configuration
30
+ attr_accessor :merchant_id, :callback_url, :client
31
+
32
+ def initialize
33
+ @client = 'https://de.zarinpal.com/pg/services/WebGate/wsdl'
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ module Zarinpal
2
+ # List of status code errors and description
3
+ module Errors
4
+ # List of status code errors and description
5
+ IDS = {
6
+ '-1' => 'Insufficient information',
7
+ '-2' => 'IP or Merchant Code is not correct',
8
+ '-3' => 'Amount should be greater than 1000',
9
+ '-4' => 'Insufficient',
10
+ '-11' => 'Requested response didn\'t find',
11
+ '-21' => 'No financial action found for this transaction',
12
+ '-22' => 'Unsuccessful transaction',
13
+ '-33' => 'Transaction price is not equal to payed amount',
14
+ '-54' => 'The request had archived'
15
+ }
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ require "savon"
2
+
3
+ module Zarinpal
4
+ # Sends a payment request to zarinpal
5
+ # @return [Zarinpal::Response]
6
+ class PaymentRequest
7
+ attr_accessor :amount, :description, :email, :mobile
8
+ attr_reader :response
9
+
10
+ # @note A hash of parameters should be send to this class
11
+ # @example
12
+ # PaymentRequest.new(amount: 10000, description: 'sth...', email: 'example@example.com')
13
+ #
14
+ # @param args [Hash] hash of params to send requests
15
+ # @option args [Integer] :amount price of the request
16
+ # @option args [Integer] :description description of transaction
17
+ # @option args [String] :email ('') email of buyer
18
+ # @option args [String] :mobile ('') mobile number of buyer
19
+ def initialize(args = {})
20
+ @amount = args.fetch(:amount)
21
+ @description = args.fetch(:description)
22
+ @email = args.fetch(:email, '')
23
+ @mobile = args.fetch(:mobile, '')
24
+ @client = Savon.client(wsdl: Zarinpal.configuration.client, pretty_print_xml: true)
25
+ @response = Response.new
26
+ end
27
+
28
+ # Sends the payment request to Zarinpal
29
+ #
30
+ # @return [Zarinpal::Response]
31
+ def call
32
+ response = @client.call :payment_request, message: {
33
+ 'MerchantID' => Zarinpal.configuration.merchant_id,
34
+ 'Amount' => @amount,
35
+ 'Description' => @description,
36
+ 'Email' => @email,
37
+ 'Mobile' => @mobile,
38
+ 'CallbackURL' => Zarinpal.configuration.callback_url
39
+ }
40
+
41
+ @response.validate(response.body)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ require "savon"
2
+
3
+ module Zarinpal
4
+ # Verifyes transaction with Zarinpal
5
+ class PaymentVerification
6
+ attr_reader :status, :refid
7
+
8
+ # @note A hash of parameters should be send to this class
9
+ # @example
10
+ # PaymentVerification.new(authority: 'xxx-xxx', amount: 10000)
11
+ #
12
+ # @param args [Hash] hash of params to verify transaction
13
+ # @option args [String] :authority Authority code returned from PaymentRequest
14
+ # @option args [Integer] :amount price of the request
15
+ def initialize(args = {})
16
+ @authority = args.fetch(:authority)
17
+ @amount = args.fetch(:amount)
18
+ @client = Savon.client(wsdl: Zarinpal.configuration.client, pretty_print_xml: true)
19
+ @response = Response.new
20
+ end
21
+
22
+ # Send verification request to Zarinpal
23
+ #
24
+ # @return [Zarinpal::Response]
25
+ def verify
26
+ response = @client.call :payment_verification, message: {
27
+ 'MerchantID' => Zarinpal.configuration.merchant_id,
28
+ 'Authority' => @authority,
29
+ 'Amount' => @amount
30
+ }
31
+ @response.validate(response.body)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,50 @@
1
+ module Zarinpal
2
+ # This classs manages the returned response from PaymentVerification and
3
+ # PaymentRequest. If the response is not valid (the status is not code is 100 or 101)
4
+ # it will raise an error with the corresponding description.
5
+ class Response
6
+
7
+ class ResponseError < RuntimeError; end
8
+
9
+ attr_reader :response, :authority, :status, :refid
10
+
11
+ # Checks if the transaction response returned from PaymentRequest
12
+ # or PaymentVerification is valid
13
+ #
14
+ # @param [#response Hash]
15
+ # @raise [ArgumentError] if response is nil
16
+ # @raise [ResponseError] if response is not valid
17
+ # @return [Response]
18
+ def validate(response = nil)
19
+ @response = response
20
+ perform_validation
21
+
22
+ return self
23
+ end
24
+
25
+ # Returns the validation status of response
26
+ #
27
+ # @return [boolean]
28
+ def valid?
29
+ @valid
30
+ end
31
+
32
+ private
33
+ def perform_validation
34
+ raise ArgumentError, 'not a valid response' if @response.nil?
35
+
36
+ body = @response[:payment_request_response] || @response[:payment_verification_response]
37
+ @authority = body[:authority]
38
+ @status = body[:status].to_i
39
+ @refid = body[:ref_id]
40
+
41
+ if not ['100', '101'].include?(body[:status])
42
+ @valid = false
43
+ raise ResponseError, Errors::IDS[body[:status]]
44
+ else
45
+ @valid = true
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,3 @@
1
+ module Zarinpal
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zarinpal do
4
+ before do
5
+ Zarinpal.configure do |config|
6
+ config.merchant_id = '52fbc7f4-3ca4-4b40-88ee-287f5ee8a9d4'
7
+ config.callback_url = 'http://www.m0b.ir/verify.php'
8
+ end
9
+ end
10
+
11
+ it 'responses to merchant_id' do
12
+ expect(Zarinpal.configuration.merchant_id).to eq('52fbc7f4-3ca4-4b40-88ee-287f5ee8a9d4')
13
+ end
14
+
15
+ it 'responses to client with default value' do
16
+ expect(Zarinpal.configuration.client).to eq('https://de.zarinpal.com/pg/services/WebGate/wsdl')
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zarinpal::Errors do
4
+
5
+ it { respond_to(:IDS) }
6
+
7
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zarinpal::PaymentRequest do
4
+ include Savon::SpecHelper
5
+
6
+ let(:zarin) {
7
+ Zarinpal::PaymentRequest.new(
8
+ {
9
+ amount: 10000,
10
+ description: 'sth for test'
11
+ })
12
+ }
13
+
14
+ let(:uri) { 'https://de.zarinpal.com/pg/services/WebGate/wsdl' }
15
+
16
+ before(:all) do
17
+ savon.mock!
18
+
19
+ Zarinpal.configure do |config|
20
+ config.merchant_id = '52fbc7f4-3ca4-4b40-88ee-287f5ee8a9d4'
21
+ config.callback_url = 'http://example.com/callback_url'
22
+ end
23
+ end
24
+
25
+ after(:all) { savon.unmock! }
26
+
27
+ it 'responses to call' do
28
+ expect(zarin).to respond_to(:call)
29
+ end
30
+
31
+ it 'successfully calls the server' do
32
+ message = {"MerchantID"=>"52fbc7f4-3ca4-4b40-88ee-287f5ee8a9d4", "Amount"=>10000, "Description"=>"sth for test", "Email"=>"", "Mobile"=>"", "CallbackURL"=>"http://example.com/callback_url"}
33
+
34
+ savon.expects(:payment_request).with(message: message ).returns('<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://zarinpal.com/"><SOAP-ENV:Body><ns1:PaymentRequestResponse><ns1:Status>101</ns1:Status><ns1:Authority>"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"</ns1:Authority></ns1:PaymentRequestResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>')
35
+
36
+ response = zarin.call
37
+ expect(response).to be_valid
38
+ end
39
+
40
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zarinpal::PaymentVerification, focus: true do
4
+ include Savon::SpecHelper
5
+
6
+ let(:pv) {
7
+ Zarinpal::PaymentVerification.new(
8
+ {
9
+ authority: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
10
+ amount: 10000
11
+ })
12
+ }
13
+
14
+ before(:all) do
15
+ savon.mock!
16
+
17
+ Zarinpal.configure do |config|
18
+ config.merchant_id = '52fbc7f4-3ca4-4b40-88ee-287f5ee8a9d4'
19
+ end
20
+ end
21
+
22
+ after(:all) { savon.unmock! }
23
+
24
+ it 'successfully verify the request' do
25
+ message = {"MerchantID"=>"52fbc7f4-3ca4-4b40-88ee-287f5ee8a9d4", "Authority"=>'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', "Amount"=>10000}
26
+
27
+ savon.expects(:payment_verification).with(message: message ).returns('<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://zarinpal.com/">
28
+ <SOAP-ENV:Body>
29
+ <ns1:PaymentVerificationResponse>
30
+ <ns1:Status>100</ns1:Status>
31
+ <ns1:RefID>22xxff33</ns1:RefID>
32
+ </ns1:PaymentVerificationResponse>
33
+ </SOAP-ENV:Body>
34
+ </SOAP-ENV:Envelope>')
35
+
36
+ response = pv.verify
37
+ expect(response).to be_valid
38
+ expect(response.refid).to eq('22xxff33')
39
+ expect(response.status).to eq(100)
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zarinpal::Response do
4
+ let(:response) { Zarinpal::Response.new }
5
+
6
+ before(:all) do
7
+ Zarinpal.configure do |config|
8
+ config.merchant_id = '52fbc7f4-3ca4-4b40-88ee-287f5ee8a9d4'
9
+ config.callback_url = 'http://example.com/callback_url'
10
+ end
11
+ end
12
+
13
+ it 'responses to authority and status' do
14
+ expect(response).to respond_to :authority
15
+ expect(response).to respond_to :status
16
+ end
17
+
18
+ context 'Validation' do
19
+ it 'fails validation if response is nil' do
20
+ zarin = Zarinpal::Response.new
21
+ expect{ zarin.validate }.to raise_error(ArgumentError, 'not a valid response')
22
+ end
23
+
24
+ it 'fails if status is less than 0' do
25
+ response = { payment_request_response: {status: "-2" } }
26
+ zarin = Zarinpal::Response.new
27
+ expect { zarin.validate(response) }.to raise_error(Zarinpal::Response::ResponseError, 'IP or Merchant Code is not correct')
28
+ expect(zarin).to_not be_valid
29
+ end
30
+
31
+ it 'fails if authority is less than 36 character' do
32
+ response = { payment_request_response: {authority: "this-is-wrong"} }
33
+ zarin = Zarinpal::Response.new.validate response
34
+ expect(zarin).to_not be_valid
35
+ end
36
+
37
+ it 'is successful' do
38
+ response = { payment_request_response: {authority: "x" * 36, status: 100 } }
39
+ zarin = Zarinpal::Response.new.validate response
40
+
41
+ expect(zarin).to be_valid
42
+ expect(zarin.authority).to eq("x" * 36)
43
+ end
44
+ end
45
+
46
+ end