twocheckout 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *~
2
+ *.lock
3
+ *.DS_Store
4
+ *.swp
5
+ *.out
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2012 - Craig Christenson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,176 @@
1
+ 2Checkout Ruby Library
2
+ =====================
3
+
4
+ This library provides developers with a simple set of bindings to the 2Checkout purchase routine, Instant Notification Service and Back Office API.
5
+
6
+ To use, install the `twocheckout` gem.
7
+
8
+ ```shell
9
+ gem install twocheckout
10
+ ```
11
+
12
+ Or import into your Gemfile.
13
+
14
+ ```ruby
15
+ gem "twocheckout", "~> 0.1.0"
16
+ ```
17
+
18
+ Full documentation for each binding is provided in the **[Wiki](https://github.com/craigchristenson/2checkout-ruby/wiki)**.
19
+
20
+
21
+ Example API Usage
22
+ -----------------
23
+
24
+ *Example Usage:*
25
+
26
+ ```ruby
27
+ Twocheckout::API.credentials = { :username => 'APIuser1817037', :password => 'APIpass1817037' }
28
+
29
+ sale = Twocheckout::Sale.find(:sale_id => 4838212958)
30
+ sale.stop_recurring!
31
+ ```
32
+
33
+ *Example Response:*
34
+
35
+ ```ruby
36
+ [
37
+ #<Twocheckout: : LineItem: 4838213015>{
38
+ "affiliate_vendor_id"=>nil,
39
+ "billing"=>#<Twocheckout: : HashObject: 70259731127120>{
40
+ "amount"=>"0.01",
41
+ "bill_method"=>"paypal_int",
42
+ "billing_id"=>"4838213024",
43
+ "customer_amount"=>"0.01",
44
+ "customer_id"=>"4838212964",
45
+ "date_deposited"=>nil,
46
+ "date_end"=>nil,
47
+ "date_fail"=>"2012-10-30",
48
+ "date_next"=>"2012-10-30",
49
+ "date_pending"=>"2012-10-23",
50
+ "date_start"=>"2012-10-25",
51
+ "lineitem_id"=>"4838213015",
52
+ "recurring_status"=>"active",
53
+ "status"=>"bill",
54
+ "usd_amount"=>"0.01",
55
+ "vendor_amount"=>"0.01"
56
+ },
57
+ "commission"=>nil,
58
+ "commission_affiliate_vendor_id"=>nil,
59
+ "commission_flat_rate"=>nil,
60
+ "commission_percentage"=>nil,
61
+ "commission_type"=>nil,
62
+ "commission_usd_amount"=>nil,
63
+ "customer_amount"=>"0.01",
64
+ "flat_rate"=>nil,
65
+ "installment"=>"1",
66
+ "invoice_id"=>"4838212967",
67
+ "lc_affiliate_vendor_id"=>nil,
68
+ "lc_usd_amount"=>nil,
69
+ "lineitem_id"=>"4838213015",
70
+ "linked_id"=>nil,
71
+ "options"=>[
72
+ {
73
+ "customer_surcharge"=>"0.01",
74
+ "lineitem_id"=>"4838213015",
75
+ "lineitem_option_id"=>"4838213021",
76
+ "option_name"=>"0.5",
77
+ "option_value"=>"test1",
78
+ "usd_surcharge"=>"0.01",
79
+ "vendor_surcharge"=>"0.01"
80
+ }
81
+ ],
82
+ "percentage"=>nil,
83
+ "product_description"=>"This is a test product!",
84
+ "product_duration"=>"Forever",
85
+ "product_handling"=>"0.00",
86
+ "product_id"=>"4774388564",
87
+ "product_is_cart"=>"0",
88
+ "product_name"=>"Example Product",
89
+ "product_price"=>"0.01",
90
+ "product_recurrence"=>"1 Week",
91
+ "product_startup_fee"=>nil,
92
+ "product_tangible"=>"0",
93
+ "sale_id"=>"4838212958",
94
+ "status"=>"bill",
95
+ "type"=>nil,
96
+ "usd_amount"=>"0.01",
97
+ "usd_commission"=>nil,
98
+ "vendor_amount"=>"0.01",
99
+ "vendor_product_id"=>"example123"
100
+ }
101
+ ]
102
+ ```
103
+
104
+ Example Checkout Usage:
105
+ -----------------------
106
+
107
+ *Example Usage:*
108
+
109
+ ```ruby
110
+ require "sinatra"
111
+
112
+ get '/' do
113
+ @@form = Twocheckout::Checkout.submit({ 'sid' => '1817037', 'mode' => '2CO','li_0_name' => 'Example Product', 'li_0_price' => '1.00'})
114
+ @@form
115
+ end
116
+ ```
117
+
118
+ *Example Response:*
119
+
120
+ ```html
121
+ <form id="2checkout" action="https://www.2checkout.com/checkout/spurchase" method="post">
122
+ <input type="hidden" name="sid" value="1817037" />
123
+ <input type="hidden" name="mode" value="2CO" />
124
+ <input type="hidden" name="li_0_name" value="Example Product" />
125
+ <input type="hidden" name="li_0_price" value="1.00" />
126
+ </form>
127
+ <script type="text/javascript">document.getElementById('2checkout').submit();</script>
128
+ ```
129
+
130
+ Example Return Usage:
131
+ ---------------------
132
+
133
+ *Example Usage:*
134
+
135
+ ```ruby
136
+ require "sinatra"
137
+
138
+ post '/' do
139
+ @@response = Twocheckout::ValidateResponse.purchase({:sid => 1817037, :secret => "tango", :order_number => params[:order_number], :total => params[:total], :key => params[:key]})
140
+ @@response.inspect
141
+ end
142
+ ```
143
+
144
+ *Example Response:*
145
+
146
+ ```ruby
147
+ {
148
+ :code => "PASS",
149
+ :message => "Hash Matched"
150
+ }
151
+ ```
152
+
153
+ Example INS Usage:
154
+ ------------------
155
+
156
+ *Example Usage:*
157
+
158
+ ```ruby
159
+ require "sinatra"
160
+
161
+ post '/' do
162
+ @@response = Twocheckout::ValidateResponse.notification({:sale_id => params[:sale_id], :vendor_id => 1817037, :invoice_id => params[:invoice_id], :secret => "tango", :md5_hash => params[:md5_hash]})
163
+ @@response.inspect
164
+ end
165
+ ```
166
+
167
+ *Example Response:*
168
+
169
+ ```ruby
170
+ {
171
+ :code => "PASS",
172
+ :message => "Hash Matched"
173
+ }
174
+ ```
175
+
176
+ Full documentation for each binding is provided in the **[Wiki](https://github.com/craigchristenson/2checkout-ruby/wiki)**.
@@ -0,0 +1,49 @@
1
+ require 'rest_client'
2
+ require 'json'
3
+
4
+ module Twocheckout
5
+ class API
6
+ API_BASE = 'https://www.2checkout.com/api/'
7
+
8
+ def self.credentials=(opts)
9
+ @@username = opts[:username]
10
+ @@password = opts[:password]
11
+ opts
12
+ end
13
+
14
+ def self.request(http_method, api_call, params = nil)
15
+ url = API_BASE + api_call
16
+ if http_method == :get
17
+ url += hash_to_querystring(params)
18
+ params = nil
19
+ end
20
+ opts = {
21
+ :method => http_method,
22
+ :url => url,
23
+ :headers => {
24
+ :accept => :json,
25
+ :content_type => :json,
26
+ :user_agent => "2Checkout/Ruby/," + Twocheckout::VERSION
27
+ },
28
+ :user => @@username,
29
+ :password => @@password,
30
+ :payload => params,
31
+ }
32
+ begin
33
+ response = RestClient::Request.execute(opts)
34
+ JSON.parse(response)
35
+ rescue => e
36
+ error_hash = JSON.parse(e.response)
37
+ raise TwocheckoutError.new(error_hash['errors'][0]['message']).retrieve
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def self.hash_to_querystring(hash)
44
+ return '' if hash.nil? || hash.empty?
45
+ '?' + hash.map { |k,v| "#{URI.encode(k.to_s)}=#{URI.encode(v.to_s)}" }.join('&')
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,26 @@
1
+ module Twocheckout
2
+ class Checkout
3
+
4
+ def self.form(params={})
5
+ @form = "<form id=\"2checkout\" action=\"https://www.2checkout.com/checkout/spurchase\" method=\"post\">\n";
6
+ params.each do |k,v|
7
+ @form = @form + "<input type=\"hidden\" name=\"" + k + "\" value=\"" + v.to_s + "\" />\n"
8
+ end
9
+ @form + "<input type=\"submit\" value=\"Proceed to Checkout\" />\n</form>"
10
+ end
11
+
12
+ def self.submit(params={})
13
+ @form = "<form id=\"2checkout\" action=\"https://www.2checkout.com/checkout/spurchase\" method=\"post\">\n";
14
+ params.each do |k,v|
15
+ @form = @form + "<input type=\"hidden\" name=\"" + k + "\" value=\"" + v.to_s + "\" />\n"
16
+ end
17
+ @form = @form + "</form>\n"
18
+ @form = @form + "<script type=\"text/javascript\">document.getElementById('2checkout').submit();</script>"
19
+ end
20
+
21
+ def self.link(params={}, url="https://www.2checkout.com/checkout/spurchase?")
22
+ @querystring = params.map{|k,v| "#{CGI.escape(k)}=#{CGI.escape(v)}"}.join("&")
23
+ @purchase_url = url + @querystring
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ require 'singleton'
2
+
3
+ module Twocheckout
4
+ class Company < HashObject
5
+ include Singleton
6
+
7
+ #
8
+ # Returns company info
9
+ #
10
+ def initialize
11
+ response = Twocheckout::API.request(:get, 'acct/detail_company_info')
12
+ super(response['vendor_company_info'])
13
+ end
14
+
15
+ #
16
+ # Returns contact info
17
+ #
18
+ def contact_info
19
+ if @contact_info.nil?
20
+ response = Twocheckout::API.request(:get, 'acct/detail_contact_info')
21
+ @contact_info = HashObject.new(response['vendor_contact_info'])
22
+ end
23
+ @contact_info
24
+ end
25
+
26
+ protected
27
+
28
+ def _key
29
+ self.vendor_id
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ module Twocheckout
2
+ class Coupon < HashObject
3
+
4
+ def self.find(options)
5
+ response = Twocheckout::API.request(:get, 'products/detail_coupon', options)
6
+ Coupon.new(response['coupon'])
7
+ end
8
+
9
+ def self.with_coupon_code(coupon_code)
10
+ find(:coupon_code => coupon_code)
11
+ end
12
+
13
+ def self.create(opts)
14
+ response = Twocheckout::API.request(:post, 'products/create_coupon', opts)
15
+ find(:coupon_code => response['coupon_code'])
16
+ end
17
+
18
+ def update(opts)
19
+ opts = opts.merge(:coupon_code => self.coupon_code)
20
+ Twocheckout::API.request(:post, 'products/update_coupon', opts)
21
+ response = Twocheckout::API.request(:get, 'products/detail_coupon', opts)
22
+ Coupon.new(response['coupon'])
23
+ end
24
+
25
+ def delete!
26
+ opts = {:coupon_code => self.coupon_code}
27
+ Twocheckout::API.request(:post, 'products/delete_coupon', opts)
28
+ end
29
+
30
+ def self.list(opts=nil)
31
+ Twocheckout::API.request(:get, 'products/list_coupons', opts)
32
+ end
33
+
34
+ protected
35
+
36
+ def _key
37
+ self.coupon_code
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ require "pp"
2
+
3
+ module Twocheckout
4
+ class HashObject
5
+
6
+ def initialize(hash)
7
+ @hash = hash
8
+ end
9
+
10
+ def method_missing(name)
11
+ name = name.to_s
12
+ if @hash.key? name
13
+ result = @hash[name]
14
+ if result.is_a?(Hash)
15
+ result = HashObject.new(result)
16
+ @hash[name] = result
17
+ end
18
+ if result.is_a?(Array)
19
+ new_array = []
20
+ result.each do |item|
21
+ new_item = item.is_a?(Hash) ? HashObject.new(item) : item
22
+ new_array << new_item
23
+ end
24
+ new_array.freeze
25
+ result = new_array
26
+ @hash[name] = result
27
+ end
28
+ return result
29
+ end
30
+ super.method_missing name
31
+ end
32
+
33
+ def inspect
34
+ "#<#{self.class.name}:#{self._key}> #{pp @hash}"
35
+ end
36
+
37
+ protected
38
+
39
+ def _key
40
+ self.object_id.to_s
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ module Twocheckout
2
+ class Invoice < HashObject
3
+
4
+ def self.find(options)
5
+ response = Twocheckout::API.request(:get, 'sales/detail_sale', options)
6
+ Sale.new(response['sale']).invoice[options[:invoice_id]]
7
+ end
8
+
9
+ #
10
+ # An array of all line-items in this invoice
11
+ #
12
+ def lineitems
13
+ if @lineitems.nil?
14
+ @lineitems = @hash['lineitems'].map { |li| Twocheckout::LineItem.new(li) }
15
+ @lineitems.freeze
16
+ end
17
+ @lineitems
18
+ end
19
+
20
+ #
21
+ # A hash to index line-items by id
22
+ #
23
+ def lineitem
24
+ if @lineitem.nil?
25
+ @lineitem = {}
26
+ lineitems.each { |li| @lineitem[li.lineitem_id] = li }
27
+ @lineitem.freeze
28
+ end
29
+ return @lineitem
30
+ end
31
+
32
+ #
33
+ # Refund invoice
34
+ #
35
+ def refund!(opts)
36
+ opts = opts.merge(:invoice_id => self.invoice_id)
37
+ Twocheckout::API.request(:post, 'sales/refund_invoice', opts)
38
+ end
39
+
40
+ #
41
+ # Get active recurring lineitems
42
+ #
43
+ def active_lineitems
44
+ @active_lineitems ||= lineitems.select(&:active?).freeze
45
+ end
46
+
47
+ def stop_recurring!
48
+ active_lineitems.each { |li| li.stop_recurring! }
49
+ end
50
+
51
+ protected
52
+
53
+ def _key
54
+ self.invoice_id
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,57 @@
1
+ module Twocheckout
2
+ class LineItem < HashObject
3
+
4
+ def refund!(opts)
5
+ opts = opts.merge(:lineitem_id => self.lineitem_id)
6
+ Twocheckout::API.request(:post, 'sales/refund_lineitem', opts)
7
+ end
8
+
9
+ def active?
10
+ self.billing.recurring_status == 'active'
11
+ end
12
+
13
+ def stop_recurring!
14
+ Twocheckout::API.request(:post, 'sales/stop_lineitem_recurring', lineitem_id: self.lineitem_id)
15
+ end
16
+
17
+ #
18
+ # Provide access to update existing recurring lineitems by allowing to lower the lineitem price
19
+ # and push the recurring billing date forward. This call is not currently documented in the
20
+ # 2Checkout API documentation.
21
+ #
22
+ # POST https://www.2checkout.com/api/sales/update_lineitem_recurring
23
+ #
24
+ # Parameters:
25
+ # * (required) lineitem_id: lineitem_id
26
+ # * (optional) comment: Optional comment added to sale
27
+ # * (optional) shift: days to shift next recurring payment forward
28
+ # * (optional) price: new recurring price (must be lower than previous price or else call will fail)
29
+ #
30
+ # The shift and price parameters are optional, but at least one of them must be provided for the
31
+ # call to be valid.
32
+ #
33
+ # Example Shift Date Next
34
+ # curl -X POST https://www.2checkout.com/api/sales/update_lineitem_recurring -u \
35
+ # 'username:password' -d 'lineitem_id=1234567890' -d 'shift=7' -H 'Accept: application/json'
36
+ #
37
+ # Example Update Price
38
+ # curl -X POST https://www.2checkout.com/api/sales/update_lineitem_recurring -u \
39
+ # 'username:password' -d 'lineitem_id=1234567890' -d 'price=1.00' -H 'Accept: application/json'
40
+ #
41
+ # Please note that this method cannot be used on PayPal sales as 2Checkout cannot alter the
42
+ # customer's billing agreement so this call can only update a recurring lineitem on credit card
43
+ # sales.
44
+ #
45
+ def update_recurring!(opts)
46
+ opts = opts.merge(:lineitem_id => self.lineitem_id)
47
+ Twocheckout::API.request(:post, 'sales/update_lineitem_recurring', opts)
48
+ end
49
+
50
+ protected
51
+
52
+ def _key
53
+ self.lineitem_id
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ module Twocheckout
2
+ class Option < HashObject
3
+
4
+ #
5
+ # Finds option by ID and returns a Option object
6
+ #
7
+ def self.find(options)
8
+ response = Twocheckout::API.request(:get, 'products/detail_option', options)
9
+ Option.new(response['option'][0])
10
+ end
11
+
12
+ def self.with_option_id(option_id)
13
+ find(:option_id => option_id)
14
+ end
15
+
16
+ #
17
+ # Creates a new product option
18
+ #
19
+ def self.create(opts)
20
+ response = Twocheckout::API.request(:post, 'products/create_option', opts)
21
+ find(:option_id => response['option_id'])
22
+ end
23
+
24
+ #
25
+ # Updates option and returns a new object
26
+ #
27
+ def update(opts)
28
+ opts = opts.merge(:option_id => self.option_id)
29
+ Twocheckout::API.request(:post, 'products/update_option', opts)
30
+ response = Twocheckout::API.request(:get, 'products/detail_option', opts)
31
+ Option.new(response['option'][0])
32
+ end
33
+
34
+ #
35
+ # Deletes the option and returns the response
36
+ #
37
+ def delete!
38
+ opts = {:option_id => self.option_id}
39
+ Twocheckout::API.request(:post, 'products/delete_option', opts)
40
+ end
41
+
42
+ #
43
+ # An array to index options list
44
+ #
45
+ def self.list(opts=nil)
46
+ response = Twocheckout::API.request(:get, 'products/list_options', opts)
47
+ response['options']
48
+ end
49
+
50
+ protected
51
+
52
+ def _key
53
+ self.option_id
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ module Twocheckout
2
+ class Product < HashObject
3
+
4
+ #
5
+ # Finds product by ID and returns a Product object
6
+ #
7
+ def self.find(opts)
8
+ response = Twocheckout::API.request(:get, 'products/detail_product', opts)
9
+ Product.new(response['product'])
10
+ end
11
+
12
+ def self.with_product_id(product_id)
13
+ find(:product_id => product_id)
14
+ end
15
+
16
+ #
17
+ # Creates a new product and returns the Product object
18
+ #
19
+ def self.create(opts)
20
+ response = Twocheckout::API.request(:post, 'products/create_product', opts)
21
+ find(:product_id => response['product_id'])
22
+ end
23
+
24
+ #
25
+ # Updates product and returns a new Product object
26
+ #
27
+ def update(opts)
28
+ opts = opts.merge(:product_id => self.product_id)
29
+ Twocheckout::API.request(:post, 'products/update_product', opts)
30
+ response = Twocheckout::API.request(:get, 'products/detail_product', opts)
31
+ Product.new(response['product'])
32
+ end
33
+
34
+ #
35
+ # Deletes the product and returns the response
36
+ #
37
+ def delete!
38
+ opts = {:product_id => self.product_id}
39
+ Twocheckout::API.request(:post, 'products/delete_product', opts)
40
+ end
41
+
42
+ #
43
+ # Get product list in an array
44
+ #
45
+ def self.list(opts)
46
+ response = Twocheckout::API.request(:get, 'products/list_products', opts)
47
+ response['products']
48
+ end
49
+
50
+ protected
51
+
52
+ def _key
53
+ self.product_id
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,100 @@
1
+ module Twocheckout
2
+ class Sale < HashObject
3
+
4
+ def self.find(options)
5
+ response = Twocheckout::API.request(:get, 'sales/detail_sale', options)
6
+ Sale.new(response['sale'])
7
+ end
8
+
9
+ def self.with_sale_id(sale_id)
10
+ find(:sale_id => sale_id)
11
+ end
12
+
13
+ def self.with_invoice_id(invoice_id)
14
+ find(:invoice_id => invoice_id)
15
+ end
16
+
17
+ #
18
+ # An array of all invoices in this sale
19
+ #
20
+ def invoices
21
+ if @invoices.nil?
22
+ @invoices = @hash['invoices'].map { |i| Twocheckout::Invoice.new(i) }
23
+ @invoices.freeze
24
+ end
25
+ @invoices
26
+ end
27
+
28
+ #
29
+ # A hash to index invoices by id
30
+ #
31
+ def invoice
32
+ if @invoice.nil?
33
+ @invoice = {}
34
+ invoices.each { |inv| @invoice[inv.invoice_id] = inv }
35
+ @invoice.freeze
36
+ end
37
+ return @invoice
38
+ end
39
+
40
+ #
41
+ # Refund sale
42
+ #
43
+ def refund!(opts)
44
+ opts = opts.merge(:sale_id => self.sale_id)
45
+ Twocheckout::API.request(:post, 'sales/refund_invoice', opts)
46
+ end
47
+
48
+ #
49
+ # Get active recurring lineitems from the most recent invoice
50
+ #
51
+ def active_lineitems
52
+ invoices.last.active_lineitems
53
+ end
54
+
55
+ #
56
+ # Stop all active recurring lineitems
57
+ #
58
+ def stop_recurring!
59
+ active_lineitems.each { |li| li.stop_recurring! }
60
+ end
61
+
62
+ #
63
+ # Add a sale comment
64
+ #
65
+ def comment(opts)
66
+ opts = opts.merge(:sale_id => self.sale_id)
67
+ Twocheckout::API.request(:post, 'sales/create_comment', opts)
68
+ end
69
+
70
+ #
71
+ # Mark tangible sale as shipped
72
+ #
73
+ def ship(opts)
74
+ opts = opts.merge(:sale_id => self.sale_id)
75
+ Twocheckout::API.request(:post, 'sales/mark_shipped', opts)
76
+ end
77
+
78
+ #
79
+ # Reauthorize sale
80
+ #
81
+ def reauth
82
+ Twocheckout::API.request(:post, 'sales/reauth', sale_id: self.sale_id)
83
+ end
84
+
85
+ #
86
+ # Get sale list in an array
87
+ #
88
+ def self.list(opts)
89
+ response = Twocheckout::API.request(:get, 'sales/list_sales', opts)
90
+ response['sale_summary']
91
+ end
92
+
93
+ protected
94
+
95
+ def _key
96
+ self.sale_id
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,18 @@
1
+ module Twocheckout
2
+ class TwocheckoutError < StandardError
3
+ attr_reader :message
4
+
5
+ def initialize(message)
6
+ @message = message
7
+ end
8
+
9
+ def retrieve
10
+ if @message.is_a?(Hash)
11
+ @message = JSON.generate(@message)
12
+ "#{@message}"
13
+ else
14
+ "#{@message}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ require 'digest/md5'
2
+
3
+ module Twocheckout
4
+ class ValidateResponse
5
+
6
+ # Checks against MD5 Hash
7
+ def self.valid?(arg1, arg2, arg3, arg4, key)
8
+ Digest::MD5.hexdigest("#{arg1}#{arg2}#{arg3}#{arg4}").upcase == key
9
+ end
10
+
11
+ def self.purchase(options)
12
+ options[:demo] == 'Y' ? 1 : options[:order_number]
13
+ if valid?(options[:secret], options[:sid], options[:order_number], options[:total], options[:key])
14
+ {:code => "PASS", :message => "Hash Matched"}
15
+ else
16
+ {:code => "FAIL", :message => "Hash Mismatch"}
17
+ end
18
+ end
19
+
20
+ def self.notification(options)
21
+ if valid?(options[:sale_id], options[:vendor_id], options[:invoice_id], options[:secret], options[:md5_hash])
22
+ {:code => "PASS", :message => "Hash Matched"}
23
+ else
24
+ {:code => "FAIL", :message => "Hash Mismatch"}
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module Twocheckout
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,13 @@
1
+ require "twocheckout/version"
2
+ require "twocheckout/api"
3
+ require "twocheckout/hash_object"
4
+ require "twocheckout/validate_response"
5
+ require "twocheckout/company"
6
+ require "twocheckout/lineitem"
7
+ require "twocheckout/invoice"
8
+ require "twocheckout/sale"
9
+ require "twocheckout/coupon"
10
+ require "twocheckout/product"
11
+ require "twocheckout/option"
12
+ require "twocheckout/checkout"
13
+ require "twocheckout/twocheckout_error"
@@ -0,0 +1,252 @@
1
+ require "minitest/spec"
2
+ require "minitest/autorun"
3
+ require "twocheckout"
4
+
5
+ #
6
+ # Sales
7
+ #
8
+ describe Twocheckout::Sale do
9
+ before do
10
+ Twocheckout::API.credentials = { :username => 'APIuser1817037', :password => 'APIpass1817037' }
11
+ end
12
+
13
+ #retrieve sale
14
+ it "Sale retrieve returns sale" do
15
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
16
+ assert_equal('4786293822', sale.sale_id)
17
+ end
18
+
19
+ #retrieve invoice
20
+ it "Sale retrieve returns invoice" do
21
+ invoice = Twocheckout::Sale.find({:invoice_id => 4786293831})
22
+ assert_equal('4786293831', invoice.invoice_id)
23
+ end
24
+
25
+ #retrieve sale list
26
+ it "Sale list returns list" do
27
+ sale_list = Twocheckout::Sale.list({:pagesize => 5})
28
+ assert_equal(5, sale_list.size)
29
+ end
30
+
31
+ #refund sale
32
+ it "Refunding a refunded sale returns exception" do
33
+ begin
34
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
35
+ sale.refund!({:comment => "test refund", :category => 1})
36
+ rescue Exception => e
37
+ assert_equal("Invoice was already refunded.", e.message)
38
+ end
39
+ end
40
+
41
+ #refund invoice
42
+ it "Refunding a refunded invoice returns exception" do
43
+ begin
44
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
45
+ invoice = sale.invoices.first
46
+ invoice.refund!({:comment => "test refund", :category => 1})
47
+ rescue Exception => e
48
+ assert_equal("Invoice was already refunded.", e.message)
49
+ end
50
+ end
51
+
52
+ #refund lineitem
53
+ it "Refunding a refunded lineitem returns exception" do
54
+ begin
55
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
56
+ first_invoice = sale.invoices.first
57
+ last_lineitem = first_invoice.lineitems.last
58
+ last_lineitem.refund!({:comment => "test refund", :category => 1})
59
+ rescue Exception => e
60
+ assert_equal("This lineitem cannot be refunded.", e.message)
61
+ end
62
+ end
63
+
64
+ #stop recurring lineitem
65
+ it "Stopping a stopped recurring lineitem returns exception" do
66
+ begin
67
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
68
+ result = sale.stop_recurring!
69
+ assert_equal(result, [])
70
+ rescue Exception => e
71
+ assert_equal("Lineitem is not scheduled to recur.", e.message)
72
+ end
73
+ end
74
+
75
+ #stop recurring sale
76
+ it "Stopping a stopped recurring sale returns exception" do
77
+ begin
78
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
79
+ last_invoice = sale.invoices.last
80
+ last_lineitem = last_invoice.lineitems.last
81
+ last_lineitem.stop_recurring!
82
+ rescue Exception => e
83
+ assert_equal("Lineitem is not scheduled to recur.", e.message)
84
+ end
85
+ end
86
+
87
+ #create comment
88
+ it "Creates a sale comment" do
89
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
90
+ result = sale.comment({:sale_comment => "test"})
91
+ assert_equal('Created comment successfully.', result['response_message'])
92
+ end
93
+
94
+ #mark shipped
95
+ it "Shipping an intangible sale returns exception" do
96
+ begin
97
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
98
+ sale.ship({:tracking_number => "123"})
99
+ rescue Exception => e
100
+ assert_equal("Item not shippable.", e.message)
101
+ end
102
+ end
103
+
104
+ #reauth
105
+ it "Reauthorizing a pending sale returns exception" do
106
+ begin
107
+ sale = Twocheckout::Sale.find(:sale_id => 4786293822)
108
+ sale.reauth
109
+ rescue Exception => e
110
+ assert_equal("Payment is already pending or deposited and cannot be reauthorized.", e.message)
111
+ end
112
+ end
113
+ end
114
+
115
+ #
116
+ # Products
117
+ #
118
+
119
+ describe Twocheckout::Product do
120
+ before do
121
+ Twocheckout::API.credentials = { :username => 'APIuser1817037', :password => 'APIpass1817037' }
122
+ end
123
+
124
+ # Product list
125
+ it "Product list returns array of products" do
126
+ product_list = Twocheckout::Product.list({ :pagesize => 5 })
127
+ assert_equal(product_list.size, 5)
128
+ end
129
+
130
+ # Product CRUD
131
+ it "Product create, find, update, delete is successful" do
132
+ # create
133
+ new_product = Twocheckout::Product.create({:name => "test product", :price => 1.00})
134
+ assert_equal("test product", new_product.name)
135
+ # find
136
+ product = Twocheckout::Product.find({:product_id => new_product.product_id})
137
+ assert_equal(new_product.product_id, product.product_id)
138
+ # update
139
+ product = product.update({:name => "new name"})
140
+ assert_equal("new name", product.name)
141
+ # delete
142
+ result = product.delete!
143
+ assert_equal("Product successfully deleted.", result['response_message'])
144
+ end
145
+ end
146
+
147
+ describe Twocheckout::Option do
148
+ before do
149
+ Twocheckout::API.credentials = { :username => 'APIuser1817037', :password => 'APIpass1817037' }
150
+ end
151
+
152
+ # Option list
153
+ it "Option list returns array of options" do
154
+ option_list = Twocheckout::Option.list({ :pagesize => 5 })
155
+ assert_equal(5, option_list.size)
156
+ end
157
+
158
+ # Option CRUD
159
+ it "Option create, find, update, delete is successful" do
160
+ # create
161
+ new_option = Twocheckout::Option.create({:option_name => "test option",
162
+ :option_value_name => "test option value", :option_value_surcharge => 1.00})
163
+ assert_equal("test option", new_option.option_name)
164
+ # find
165
+ option = Twocheckout::Option.find({:option_id => new_option.option_id})
166
+ assert_equal(new_option.option_id, option.option_id)
167
+ # update
168
+ option = option.update({:option_name => "new name"})
169
+ assert_equal("new name", option.option_name)
170
+ # delete
171
+ result = option.delete!
172
+ assert_equal("Option deleted successfully", result['response_message'])
173
+ end
174
+ end
175
+
176
+ describe Twocheckout::Coupon do
177
+ before do
178
+ Twocheckout::API.credentials = { :username => 'APIuser1817037', :password => 'APIpass1817037' }
179
+ end
180
+
181
+ # Coupon list
182
+ it "Coupon list returns array of coupons" do
183
+ coupon_list = Twocheckout::Coupon.list({ :pagesize => 4 })
184
+ assert_equal(4, coupon_list.size)
185
+ end
186
+
187
+ # Coupon CRUD
188
+ it "Coupon create, find, update, delete is successful" do
189
+ # create
190
+ new_coupon = Twocheckout::Coupon.create({:date_expire => "2020-01-01",
191
+ :type => "shipping", :minimum_purchase => 1.00})
192
+ assert_equal("2020-01-01", new_coupon.date_expire)
193
+ # find
194
+ coupon = Twocheckout::Coupon.find({:coupon_code => new_coupon.coupon_code})
195
+ assert_equal(new_coupon.coupon_code, coupon.coupon_code)
196
+ # update
197
+ coupon = coupon.update({:date_expire => "2020-01-02"})
198
+ assert_equal("2020-01-02", coupon.date_expire)
199
+ # delete
200
+ result = coupon.delete!
201
+ assert_equal("Coupon successfully deleted.", result['response_message'])
202
+ end
203
+ end
204
+
205
+ describe Twocheckout::ValidateResponse do
206
+ #purchase
207
+ it "Validates Purchase MD5 Hash" do
208
+ result = Twocheckout::ValidateResponse.purchase({:sid => 1817037, :secret => "tango", :order_number => 4789848870, :total => 0.01,
209
+ :key => 'CDF3E502AA1597DD4401760783432337'})
210
+ assert_equal('PASS', result[:code])
211
+ end
212
+
213
+ #notification
214
+ it "Validates Notification MD5 Hash" do
215
+ result = Twocheckout::ValidateResponse.notification({:sale_id => 4789848870, :vendor_id => 1817037, :invoice_id => 4789848879, :secret => "tango",
216
+ :md5_hash => '827220324C722873694758F38D8D3624'})
217
+ assert_equal('PASS', result[:code])
218
+ end
219
+ end
220
+
221
+ describe Twocheckout::Checkout do
222
+ #submit
223
+ it "Submit return a form + JS to submit" do
224
+ form = Twocheckout::Checkout.submit({ 'sid' => '1817037', 'cart_order_id' => 'Example Sale', 'total' => '1.00'})
225
+ @form = "<form id=\"2checkout\" action=\"https://www.2checkout.com/checkout/spurchase\" method=\"post\">\n" +
226
+ "<input type=\"hidden\" name=\"sid\" value=\"1817037\" />\n" +
227
+ "<input type=\"hidden\" name=\"cart_order_id\" value=\"Example Sale\" />\n" +
228
+ "<input type=\"hidden\" name=\"total\" value=\"1.00\" />\n" +
229
+ "</form>\n" +
230
+ "<script type=\"text/javascript\">document.getElementById('2checkout').submit();</script>"
231
+ assert_equal(form, @form)
232
+ end
233
+
234
+ #form
235
+ it "Form returns a form" do
236
+ form = Twocheckout::Checkout.form({ 'sid' => '1817037', 'cart_order_id' => 'Example Sale', 'total' => '1.00'})
237
+ @form = "<form id=\"2checkout\" action=\"https://www.2checkout.com/checkout/spurchase\" method=\"post\">\n" +
238
+ "<input type=\"hidden\" name=\"sid\" value=\"1817037\" />\n" +
239
+ "<input type=\"hidden\" name=\"cart_order_id\" value=\"Example Sale\" />\n" +
240
+ "<input type=\"hidden\" name=\"total\" value=\"1.00\" />\n" +
241
+ "<input type=\"submit\" value=\"Proceed to Checkout\" />\n" +
242
+ "</form>"
243
+ assert_equal(form, @form)
244
+ end
245
+
246
+ #link
247
+ it "Link returns a link" do
248
+ link = Twocheckout::Checkout.link({ 'sid' => '1817037', 'cart_order_id' => 'Example Sale', 'total' => '1.00'})
249
+ @link = "https://www.2checkout.com/checkout/spurchase?sid=1817037&cart_order_id=Example+Sale&total=1.00"
250
+ assert_equal(link, @link)
251
+ end
252
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
3
+
4
+ Gem::Specification.new do |s|
5
+ s.platform = Gem::Platform::RUBY
6
+ s.name = 'twocheckout'
7
+ s.version = '0.1.1'
8
+ s.summary = '2Checkout Ruby Library'
9
+ s.description = '0.1.1'
10
+ s.summary = '2Checkout Ruby Library'
11
+ s.author = "Craig Christenson", "Ernesto Garcia"
12
+ s.email = 'christensoncraig@gmail.com'
13
+ s.homepage = 'https://github.com/craigchristenson'
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.add_dependency('rest-client', '~> 1.4')
18
+ s.require_paths = %w{lib}
19
+ s.requirements << 'none'
20
+
21
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twocheckout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -19,7 +19,7 @@ dependencies:
19
19
  requirements:
20
20
  - - ~>
21
21
  - !ruby/object:Gem::Version
22
- version: 1.6.7
22
+ version: '1.4'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -27,16 +27,33 @@ dependencies:
27
27
  requirements:
28
28
  - - ~>
29
29
  - !ruby/object:Gem::Version
30
- version: 1.6.7
31
- description: 0.1.0
32
- email:
33
- - christensoncraig@gmail.com
34
- - ernesto+git@gnapse.com
30
+ version: '1.4'
31
+ description: 0.1.1
32
+ email: christensoncraig@gmail.com
35
33
  executables: []
36
34
  extensions: []
37
35
  extra_rdoc_files: []
38
- files: []
39
- homepage: http://github.com/craigchristenson
36
+ files:
37
+ - .gitignore
38
+ - LICENSE
39
+ - README.md
40
+ - lib/twocheckout.rb
41
+ - lib/twocheckout/api.rb
42
+ - lib/twocheckout/checkout.rb
43
+ - lib/twocheckout/company.rb
44
+ - lib/twocheckout/coupon.rb
45
+ - lib/twocheckout/hash_object.rb
46
+ - lib/twocheckout/invoice.rb
47
+ - lib/twocheckout/lineitem.rb
48
+ - lib/twocheckout/option.rb
49
+ - lib/twocheckout/product.rb
50
+ - lib/twocheckout/sale.rb
51
+ - lib/twocheckout/twocheckout_error.rb
52
+ - lib/twocheckout/validate_response.rb
53
+ - lib/twocheckout/version.rb
54
+ - test/test_twocheckout.rb
55
+ - twocheckout.gemspec
56
+ homepage: https://github.com/craigchristenson
40
57
  licenses: []
41
58
  post_install_message:
42
59
  rdoc_options: []
@@ -54,10 +71,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
71
  - - ! '>='
55
72
  - !ruby/object:Gem::Version
56
73
  version: '0'
57
- requirements: []
74
+ requirements:
75
+ - none
58
76
  rubyforge_project:
59
77
  rubygems_version: 1.8.24
60
78
  signing_key:
61
79
  specification_version: 3
62
- summary: Ruby wrapper for 2Checkout API
63
- test_files: []
80
+ summary: 2Checkout Ruby Library
81
+ test_files:
82
+ - test/test_twocheckout.rb