express-checkout 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e016efaa655a370f36a5480ef0b65c28590c576d
4
- data.tar.gz: 6c4e0e630d86d54107877f0c9274068f34108091
3
+ metadata.gz: c7019fc3b0f27e0ba38c68edff4bc4c07d87f3c1
4
+ data.tar.gz: 77fc1279c58d5373b98d5c36944f51821899073f
5
5
  SHA512:
6
- metadata.gz: 69da75217e4720eecc22b99d0f2999f42912f27a332e66233a3f1ad0d07d1070579cad3f9ba3d9b04f8b3c35ed56c466bfe5355bc47af0bfe45e59bb04dfe53e
7
- data.tar.gz: 4408c17eac1331e66895b369ac241eaef7b14829fdad914f070cc09dd0f2a1f6ea9be460b1da29a8e6b108a3cd8df3551f399d14ef9e237241b59b07f8666dc8
6
+ metadata.gz: be6b78d98106f7a75282cc47c4534dd6ec03682b7a267e8dc9ff8b44d10a0201b85089e52cc324410ce061b4ad47269b0f56b37bc09909687334acd1f9c0105c
7
+ data.tar.gz: 4f799585716cfedf9eb60b7443b820880927896db20579e225cb8d51f8b0e29fc60e47112ab6b64c54e21e7b9c99d042026d029e7811800da3792db4f6ebd0d0
@@ -1,11 +1,11 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'express/checkout/version'
4
+ require 'express/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "express-checkout"
8
- spec.version = Express::Checkout::VERSION
8
+ spec.version = Express::VERSION
9
9
  spec.authors = ["Wei-Yi Chiu"]
10
10
  spec.email = ["bird1204@gmail.com"]
11
11
 
@@ -27,6 +27,12 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
+ spec.add_dependency "activesupport", ">= 2.3"
31
+ spec.add_dependency "rest-client"
32
+ spec.add_dependency "attr_required", ">= 0.0.5"
30
33
  spec.add_development_dependency "bundler", "~> 1.9"
31
- spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rake", ">= 0.8"
35
+ spec.add_development_dependency "simplecov"
36
+ spec.add_development_dependency "rspec", "< 2.99"
37
+ spec.add_development_dependency "fakeweb", ">= 1.3.0"
32
38
  end
data/lib/express.rb ADDED
@@ -0,0 +1,85 @@
1
+ require 'express/checkout/version'
2
+ require 'logger'
3
+ require 'active_support'
4
+ require 'active_support/core_ext'
5
+ require 'attr_required'
6
+ require 'attr_optional'
7
+ require 'rest_client'
8
+
9
+ module Express
10
+ mattr_accessor :api_version
11
+ self.api_version = '88.0'
12
+
13
+ ENDPOINT = {
14
+ production: 'https://www.paypal.com/cgi-bin/webscr',
15
+ sandbox: 'https://www.sandbox.paypal.com/cgi-bin/webscr'
16
+ }
17
+ POPUP_ENDPOINT = {
18
+ production: 'https://www.paypal.com/incontext',
19
+ sandbox: 'https://www.sandbox.paypal.com/incontext'
20
+ }
21
+
22
+ def self.endpoint
23
+ if sandbox?
24
+ Paypal::ENDPOINT[:sandbox]
25
+ else
26
+ Paypal::ENDPOINT[:production]
27
+ end
28
+ end
29
+ def self.popup_endpoint
30
+ if sandbox?
31
+ Paypal::POPUP_ENDPOINT[:sandbox]
32
+ else
33
+ Paypal::POPUP_ENDPOINT[:production]
34
+ end
35
+ end
36
+
37
+ def self.log(message, mode = :info)
38
+ logger.send mode, message
39
+ end
40
+ def self.logger
41
+ @@logger
42
+ end
43
+ def self.logger=(logger)
44
+ @@logger = logger
45
+ end
46
+
47
+ @@logger = Logger.new(STDERR)
48
+ @@logger.progname = 'Express::Checkout'
49
+
50
+ def self.sandbox?
51
+ @@sandbox
52
+ end
53
+ def self.sandbox!
54
+ self.sandbox = true
55
+ end
56
+ def self.sandbox=(boolean)
57
+ @@sandbox = boolean
58
+ end
59
+ self.sandbox = false
60
+ end
61
+
62
+ require 'paypal/util'
63
+ require 'paypal/exception'
64
+ require 'paypal/exception/http_error'
65
+ require 'paypal/exception/api_error'
66
+ require 'paypal/base'
67
+ require 'paypal/ipn'
68
+ require 'paypal/nvp/request'
69
+ require 'paypal/nvp/response'
70
+ require 'paypal/payment/common/amount'
71
+ require 'paypal/express/request'
72
+ require 'paypal/express/response'
73
+ require 'paypal/payment/request'
74
+ require 'paypal/payment/request/item'
75
+ require 'paypal/payment/response'
76
+ require 'paypal/payment/response/info'
77
+ require 'paypal/payment/response/item'
78
+ require 'paypal/payment/response/payer'
79
+ require 'paypal/payment/response/reference'
80
+ require 'paypal/payment/response/refund'
81
+ require 'paypal/payment/response/address'
82
+ require 'paypal/payment/recurring'
83
+ require 'paypal/payment/recurring/activation'
84
+ require 'paypal/payment/recurring/billing'
85
+ require 'paypal/payment/recurring/summary'
@@ -0,0 +1,19 @@
1
+ module Express
2
+ class Base
3
+ include AttrRequired, AttrOptional, Util
4
+
5
+ def initialize(attributes = {})
6
+ if attributes.is_a?(Hash)
7
+ (required_attributes + optional_attributes).each do |key|
8
+ value = if numeric_attribute?(key)
9
+ Util.to_numeric(attributes[key])
10
+ else
11
+ attributes[key]
12
+ end
13
+ send "#{key}=", value
14
+ end
15
+ end
16
+ attr_missing!
17
+ end
18
+ end
19
+ end
@@ -1,7 +1 @@
1
- require "express/checkout/version"
2
-
3
- module Express
4
- module Checkout
5
- # Your code goes here...
6
- end
7
- end
1
+ require 'paypal'
@@ -0,0 +1,194 @@
1
+ module Express
2
+ module Checkout
3
+ class Request < NVP::Request
4
+
5
+ # Common
6
+
7
+ def setup(payment_requests, return_url, cancel_url, options = {})
8
+ params = {
9
+ :RETURNURL => return_url,
10
+ :CANCELURL => cancel_url
11
+ }
12
+ if options[:no_shipping]
13
+ params[:REQCONFIRMSHIPPING] = 0
14
+ params[:NOSHIPPING] = 1
15
+ end
16
+
17
+ params[:ALLOWNOTE] = 0 if options[:allow_note] == false
18
+
19
+ {
20
+ :solution_type => :SOLUTIONTYPE,
21
+ :landing_page => :LANDINGPAGE,
22
+ :email => :EMAIL,
23
+ :brand => :BRANDNAME,
24
+ :locale => :LOCALECODE,
25
+ :logo => :LOGOIMG,
26
+ :cart_border_color => :CARTBORDERCOLOR,
27
+ :payflow_color => :PAYFLOWCOLOR
28
+ }.each do |option_key, param_key|
29
+ params[param_key] = options[option_key] if options[option_key]
30
+ end
31
+ Array(payment_requests).each_with_index do |payment_request, index|
32
+ params.merge! payment_request.to_params(index)
33
+ end
34
+ response = self.request :SetExpressCheckout, params
35
+ Response.new response, options
36
+ end
37
+
38
+ def details(token)
39
+ response = self.request :GetExpressCheckoutDetails, {:TOKEN => token}
40
+ Response.new response
41
+ end
42
+
43
+ def transaction_details(transaction_id)
44
+ response = self.request :GetTransactionDetails, {:TRANSACTIONID=> transaction_id}
45
+ Response.new response
46
+ end
47
+
48
+ def checkout!(token, payer_id, payment_requests)
49
+ params = {
50
+ :TOKEN => token,
51
+ :PAYERID => payer_id
52
+ }
53
+ Array(payment_requests).each_with_index do |payment_request, index|
54
+ params.merge! payment_request.to_params(index)
55
+ end
56
+ response = self.request :DoExpressCheckoutPayment, params
57
+ Response.new response
58
+ end
59
+
60
+ def capture!(authorization_id, amount, currency_code, complete_type = 'Complete')
61
+ params = {
62
+ :AUTHORIZATIONID => authorization_id,
63
+ :COMPLETETYPE => complete_type,
64
+ :AMT => amount,
65
+ :CURRENCYCODE => currency_code
66
+ }
67
+
68
+ response = self.request :DoCapture, params
69
+ Response.new response
70
+ end
71
+
72
+ def void!(authorization_id, params={})
73
+ params = {
74
+ :AUTHORIZATIONID => authorization_id,
75
+ :NOTE => params[:note]
76
+ }
77
+
78
+ response = self.request :DoVoid, params
79
+ Response.new response
80
+ end
81
+
82
+ # Recurring Payment Specific
83
+
84
+ def subscribe!(token, recurring_profile)
85
+ params = {
86
+ :TOKEN => token
87
+ }
88
+ params.merge! recurring_profile.to_params
89
+ response = self.request :CreateRecurringPaymentsProfile, params
90
+ Response.new response
91
+ end
92
+
93
+ def subscription(profile_id)
94
+ params = {
95
+ :PROFILEID => profile_id
96
+ }
97
+ response = self.request :GetRecurringPaymentsProfileDetails, params
98
+ Response.new response
99
+ end
100
+
101
+ def renew!(profile_id, action, options = {})
102
+ params = {
103
+ :PROFILEID => profile_id,
104
+ :ACTION => action
105
+ }
106
+ if options[:note]
107
+ params[:NOTE] = options[:note]
108
+ end
109
+ response = self.request :ManageRecurringPaymentsProfileStatus, params
110
+ Response.new response
111
+ end
112
+
113
+ def suspend!(profile_id, options = {})
114
+ renew!(profile_id, :Suspend, options)
115
+ end
116
+
117
+ def cancel!(profile_id, options = {})
118
+ renew!(profile_id, :Cancel, options)
119
+ end
120
+
121
+ def reactivate!(profile_id, options = {})
122
+ renew!(profile_id, :Reactivate, options)
123
+ end
124
+
125
+
126
+ # Reference Transaction Specific
127
+
128
+ def agree!(token, options = {})
129
+ params = {
130
+ :TOKEN => token
131
+ }
132
+ if options[:max_amount]
133
+ params[:MAXAMT] = Util.formatted_amount options[:max_amount]
134
+ end
135
+ response = self.request :CreateBillingAgreement, params
136
+ Response.new response
137
+ end
138
+
139
+ def agreement(reference_id)
140
+ params = {
141
+ :REFERENCEID => reference_id
142
+ }
143
+ response = self.request :BillAgreementUpdate, params
144
+ Response.new response
145
+ end
146
+
147
+ def charge!(reference_id, amount, options = {})
148
+ params = {
149
+ :REFERENCEID => reference_id,
150
+ :AMT => Util.formatted_amount(amount),
151
+ :PAYMENTACTION => options[:payment_action] || :Sale
152
+ }
153
+ if options[:currency_code]
154
+ params[:CURRENCYCODE] = options[:currency_code]
155
+ end
156
+ response = self.request :DoReferenceTransaction, params
157
+ Response.new response
158
+ end
159
+
160
+ def revoke!(reference_id)
161
+ params = {
162
+ :REFERENCEID => reference_id,
163
+ :BillingAgreementStatus => :Canceled
164
+ }
165
+ response = self.request :BillAgreementUpdate, params
166
+ Response.new response
167
+ end
168
+
169
+
170
+ # Refund Specific
171
+
172
+ def refund!(transaction_id, options = {})
173
+ params = {
174
+ :TRANSACTIONID => transaction_id,
175
+ :REFUNDTYPE => :Full
176
+ }
177
+ if options[:invoice_id]
178
+ params[:INVOICEID] = options[:invoice_id]
179
+ end
180
+ if options[:type]
181
+ params[:REFUNDTYPE] = options[:type]
182
+ params[:AMT] = options[:amount]
183
+ params[:CURRENCYCODE] = options[:currency_code]
184
+ end
185
+ if options[:note]
186
+ params[:NOTE] = options[:note]
187
+ end
188
+ response = self.request :RefundTransaction, params
189
+ Response.new response
190
+ end
191
+
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,35 @@
1
+ module Express
2
+ module Check
3
+ class Response < NVP::Response
4
+ attr_accessor :pay_on_paypal, :mobile
5
+
6
+ def initialize(response, options = {})
7
+ super response
8
+ @pay_on_paypal = options[:pay_on_paypal]
9
+ @mobile = options[:mobile]
10
+ end
11
+
12
+ def redirect_uri
13
+ endpoint = URI.parse Paypal.endpoint
14
+ endpoint.query = query(:with_cmd).to_query
15
+ endpoint.to_s
16
+ end
17
+
18
+ def popup_uri
19
+ endpoint = URI.parse Paypal.popup_endpoint
20
+ endpoint.query = query.to_query
21
+ endpoint.to_s
22
+ end
23
+
24
+ private
25
+
26
+ def query(with_cmd = false)
27
+ _query_ = {:token => self.token}
28
+ _query_.merge!(:cmd => '_express-checkout') if with_cmd
29
+ _query_.merge!(:cmd => '_express-checkout-mobile') if mobile
30
+ _query_.merge!(:useraction => 'commit') if pay_on_paypal
31
+ _query_
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,4 @@
1
+ module Express
2
+ class Exception < StandardError
3
+ end
4
+ end
@@ -0,0 +1,94 @@
1
+ module Express
2
+ class Exception
3
+ class APIError < Exception
4
+ attr_accessor :response
5
+ def initialize(response = {})
6
+ @response = if response.is_a?(Hash)
7
+ Response.new response
8
+ else
9
+ response
10
+ end
11
+ end
12
+
13
+ def message
14
+ if response.respond_to?(:short_messages) && response.short_messages.any?
15
+ "PayPal API Error: " <<
16
+ response.short_messages.map{ |m| "'#{m}'" }.join(", ")
17
+ else
18
+ "PayPal API Error"
19
+ end
20
+ end
21
+
22
+ class Response
23
+ cattr_reader :attribute_mapping
24
+ @@attribute_mapping = {
25
+ :ACK => :ack,
26
+ :BUILD => :build,
27
+ :CORRELATIONID => :correlation_id,
28
+ :TIMESTAMP => :timestamp,
29
+ :VERSION => :version,
30
+ :ORDERTIME => :order_time,
31
+ :PENDINGREASON => :pending_reason,
32
+ :PAYMENTSTATUS => :payment_status,
33
+ :PAYMENTTYPE => :payment_type,
34
+ :REASONCODE => :reason_code,
35
+ :TRANSACTIONTYPE => :transaction_type
36
+ }
37
+ attr_accessor *@@attribute_mapping.values
38
+ attr_accessor :raw, :details
39
+ alias_method :colleration_id, :correlation_id # NOTE: I made a typo :p
40
+
41
+ class Detail
42
+ cattr_reader :attribute_mapping
43
+ @@attribute_mapping = {
44
+ :ERRORCODE => :error_code,
45
+ :SEVERITYCODE => :severity_code,
46
+ :LONGMESSAGE => :long_message,
47
+ :SHORTMESSAGE => :short_message
48
+ }
49
+ attr_accessor *@@attribute_mapping.values
50
+
51
+ def initialize(attributes = {})
52
+ @raw = attributes
53
+ attrs = attributes.dup
54
+ @@attribute_mapping.each do |key, value|
55
+ self.send "#{value}=", attrs.delete(key)
56
+ end
57
+
58
+ # warn ignored params
59
+ attrs.each do |key, value|
60
+ Paypal.log "Ignored Parameter (#{self.class}): #{key}=#{value}", :warn
61
+ end
62
+ end
63
+ end
64
+
65
+ def initialize(attributes = {})
66
+ attrs = attributes.dup
67
+ @raw = attributes
68
+ @@attribute_mapping.each do |key, value|
69
+ self.send "#{value}=", attrs.delete(key)
70
+ end
71
+ details = []
72
+ attrs.keys.each do |attribute|
73
+ key, index = attribute.to_s.scan(/^L_(\S+)(\d+)$/).first
74
+ next if [key, index].any?(&:blank?)
75
+ details[index.to_i] ||= {}
76
+ details[index.to_i][key.to_sym] = attrs.delete(attribute)
77
+ end
78
+ @details = details.collect do |_attrs_|
79
+ Detail.new _attrs_
80
+ end
81
+
82
+ # warn ignored params
83
+ attrs.each do |key, value|
84
+ Paypal.log "Ignored Parameter (#{self.class}): #{key}=#{value}", :warn
85
+ end
86
+ end
87
+
88
+ def short_messages
89
+ details.map(&:short_message).compact
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end