paytrace 0.1.23 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/paytrace/address.rb +2 -0
  3. data/lib/paytrace/api/gateway.rb +19 -4
  4. data/lib/paytrace/api/request.rb +72 -28
  5. data/lib/paytrace/api/response.rb +19 -11
  6. data/lib/paytrace/batch_operations.rb +8 -30
  7. data/lib/paytrace/check_transaction.rb +119 -84
  8. data/lib/paytrace/configuration.rb +2 -0
  9. data/lib/paytrace/customer.rb +95 -97
  10. data/lib/paytrace/debug.rb +36 -0
  11. data/lib/paytrace/email_receipt_request.rb +4 -28
  12. data/lib/paytrace/recurring_transaction.rb +20 -67
  13. data/lib/paytrace/transaction.rb +680 -267
  14. data/lib/paytrace/version.rb +1 -1
  15. data/lib/paytrace.rb +0 -4
  16. data/paytrace.gemspec +1 -0
  17. data/run_all_integrations.sh +15 -0
  18. data/test/paytrace/api/gateway_spec.rb +8 -0
  19. data/test/paytrace/api/request_spec.rb +84 -28
  20. data/test/paytrace/api/response_spec.rb +2 -2
  21. data/test/paytrace/batch_operations_spec.rb +5 -5
  22. data/test/paytrace/{check_transactions_spec.rb → check_transaction_spec.rb} +40 -19
  23. data/test/paytrace/customer_spec.rb +86 -110
  24. data/test/paytrace/email_receipt_request_spec.rb +9 -8
  25. data/test/paytrace/level3_data_spec.rb +28 -2
  26. data/test/paytrace/recurring_transaction_spec.rb +8 -16
  27. data/test/paytrace/transaction_spec.rb +300 -330
  28. data/test/scripts/run_adjust_amount.rb +1 -1
  29. data/test/scripts/run_attach_signature.rb +2 -2
  30. data/test/scripts/run_calculate_shipping_costs.rb +2 -3
  31. data/test/scripts/run_change_password.rb +2 -0
  32. data/test/scripts/run_check_transactions.rb +2 -3
  33. data/test/scripts/run_create_customer.rb +16 -23
  34. data/test/scripts/run_email_request.rb +3 -5
  35. data/test/scripts/run_export_batches.rb +6 -3
  36. data/test/scripts/run_export_customers.rb +1 -1
  37. data/test/scripts/run_export_transactions.rb +2 -2
  38. data/test/scripts/run_level3_data.rb +1 -1
  39. data/test/scripts/run_recur_payments_integration.rb +24 -32
  40. data/test/scripts/run_settle_transaction.rb +2 -2
  41. data/test/test_helper.rb +12 -1
  42. metadata +19 -7
  43. data/lib/paytrace/credit_card.rb +0 -32
  44. data/test/paytrace/credit_card_spec.rb +0 -26
@@ -1,9 +1,9 @@
1
1
  module PayTrace
2
2
  # Abstracts the idea of a merchant's customer. Also provides numerous helper methods to aid in managing customers.
3
3
  class Customer
4
+ # :nodoc:
4
5
  attr :id, :customer_id
5
6
 
6
- # :nodoc:
7
7
  CREATE_CUSTOMER = "CreateCustomer"
8
8
  UPDATE_CUSTOMER = "UpdateCustomer"
9
9
  DELETE_CUSTOMER = "DeleteCustomer"
@@ -11,29 +11,53 @@ module PayTrace
11
11
  EXPORT_INACTIVE_CUSTOMERS = "ExportInactiveCustomers"
12
12
  EXPORT_CUSTOMERS_RESPONSE = "CUSTOMERRECORD"
13
13
 
14
+ BILLING_AND_SHIPPING_ADDRESS_FIELDS = [
15
+ :billing_name,
16
+ :billing_address,
17
+ :billing_address2,
18
+ :billing_city,
19
+ :billing_state,
20
+ :billing_postal_code,
21
+ :billing_country,
22
+ :shipping_name,
23
+ :shipping_address,
24
+ :shipping_address2,
25
+ :shipping_city,
26
+ :shipping_state,
27
+ :shipping_postal_code,
28
+ :shipping_region,
29
+ :shipping_country
30
+ ]
31
+
32
+ CUSTOMER_OPTIONAL_PARAMS = BILLING_AND_SHIPPING_ADDRESS_FIELDS + [
33
+ :email,
34
+ :customer_phone,
35
+ :customer_fax,
36
+ :customer_password,
37
+ :account_number,
38
+ :routing_number,
39
+ :discretionary_data
40
+ ]
41
+
14
42
  # :doc:
15
- # Initializer. Only param is:
16
- # *customer_id* -- the merchant-generated customer ID, if present
17
- def initialize(customer_id = nil)
18
- @customer_id = customer_id
19
- end
20
43
 
21
44
  # See http://help.paytrace.com/api-update-customer-profile
45
+ #
46
+ # Updates the customer's information from parameters hash.
47
+ #
48
+ # Required parameters:
49
+ #
50
+ # * *:customer_id* -- the customer ID of the profile to update
51
+ #
22
52
  # Updates the customer's information from parameters hash. See the self.from_cc_info and self.from_transaction_id for
23
53
  # information on the permitted parameters. Immediately updates the profile.
24
- def update(params = {})
25
- send_request(UPDATE_CUSTOMER, params)
26
- end
27
-
28
- # See http://help.paytrace.com/api-delete-customer-profile
29
- # Sends a request to the server to delete a given customer. No parameters; the customer ID is assumed to be set on
30
- # this object.
31
- def delete
32
- request = PayTrace::API::Request.new
33
- request.set_param(:method, DELETE_CUSTOMER)
34
- request.set_param(:customer_id, @customer_id)
35
- gateway = PayTrace::API::Gateway.new
36
- gateway.send_request(request)
54
+ def self.update(params = {})
55
+ PayTrace::API::Gateway.send_request(UPDATE_CUSTOMER, params, [:customer_id], CUSTOMER_OPTIONAL_PARAMS + [
56
+ :card_number,
57
+ :expiration_month,
58
+ :expiration_year,
59
+ :new_customer_id
60
+ ])
37
61
  end
38
62
 
39
63
  # See http://help.paytrace.com/api-exporting-customer-profiles for more information.
@@ -43,49 +67,54 @@ module PayTrace
43
67
  # * *:transaction_user* -- the user name of the PayTrace user who created or processed the customer or transaction you are trying to export
44
68
  # * *:return_bin* -- if set to "Y", card numbers from ExportTranx and ExportCustomers requests will include the first 6 and last 4 digits of the card number
45
69
  def self.export(params = {})
46
- # CUSTID, EMAIL, USER, RETURNBIN
47
- request = PayTrace::API::Request.new
48
- request.set_param(:method, EXPORT_CUSTOMERS)
49
- request.set_param(:customer_id, params[:customer_id])
50
- request.set_param(:email, params[:email])
51
- request.set_param(:transaction_user, params[:transaction_user])
52
- request.set_param(:return_bin, params[:return_bin])
53
- gateway = PayTrace::API::Gateway.new
54
- response = gateway.send_request(request, [EXPORT_CUSTOMERS_RESPONSE])
55
-
56
- unless response.has_errors?
57
- response.values[EXPORT_CUSTOMERS_RESPONSE]
58
- end
70
+ response = PayTrace::API::Gateway.send_request(EXPORT_CUSTOMERS, params, [], [:customer_id, :email, :transaction_user, :return_bin])
71
+ response.parse_records(EXPORT_CUSTOMERS_RESPONSE)
59
72
  end
60
73
 
61
74
  # See http://help.paytrace.com/api-exporting-inactive-customers
62
75
  # Exports the profiles of customers who have been inactive for a certain length of time. Params:
63
76
  # *:days_inactive* -- the number of days of inactivity to search for
64
77
  def self.export_inactive(params = {})
65
- request = PayTrace::API::Request.new
66
- request.set_param(:method, EXPORT_INACTIVE_CUSTOMERS)
67
- request.set_param(:days_inactive, params[:days_inactive])
68
- gateway = PayTrace::API::Gateway.new
69
- response = gateway.send_request(request, [EXPORT_CUSTOMERS_RESPONSE])
70
-
71
- unless response.has_errors?
72
- response.values[EXPORT_CUSTOMERS_RESPONSE]
73
- end
78
+ response = PayTrace::API::Gateway.send_request(EXPORT_INACTIVE_CUSTOMERS, params, [:days_inactive], [])
79
+ response.parse_records(EXPORT_CUSTOMERS_RESPONSE)
74
80
  end
75
81
 
76
82
  # See http://help.paytrace.com/api-delete-customer-profile
77
83
  # Performs the same functionality as Customer.delete, but saves a step by not requiring the user to instantiate a new Customer object first. Params:
78
84
  # *customer_id* -- the merchant-assigned customer ID of the profile to delete
79
85
  def self.delete(customer_id)
80
- Customer.new(customer_id).delete
86
+ PayTrace::API::Gateway.send_request(DELETE_CUSTOMER, {customer_id: customer_id}, [:customer_id])
81
87
  end
82
88
 
83
89
  # See http://help.paytrace.com/api-create-customer-profile
84
- # Creates a new customer profile from credit card information. Params:
85
- # *:customer_id* -- customer ID to use
86
- # *:billing_address* -- a PayTrace::Address object; at minimum the billing name must be filled out
87
- # *:credit_card* -- a PayTrace::CreditCard object
88
- # *:shipping_address* -- a PayTrace::Address object representing the shipping address
90
+ #
91
+ # Creates a new customer profile from credit card information.
92
+ #
93
+ # Required parameters:
94
+ #
95
+ # * *:customer_id* -- customer ID to use
96
+ # * *:billing_name* -- the billing name for this transaction
97
+ # * *:card_number* -- a credit card number
98
+ # * *:expiration_month* -- the expiration month for the credit card
99
+ # * *:expiration_year* -- the expiration year for the credit card
100
+ #
101
+ # Optional parameters:
102
+ #
103
+ # * *:billing_name* -- the billing name for this transaction
104
+ # * *:billing_address* -- the billing street address for this transaction
105
+ # * *:billing_address2* -- the billing street address second line (e.g., apartment, suite) for this transaction
106
+ # * *:billing_city* -- the billing city for this transaction
107
+ # * *:billing_state* -- the billing state for this transaction
108
+ # * *:billing_postal_code* -- the billing zip code for this transaction
109
+ # * *:billing_country* -- the billing country for this transaction
110
+ # * *:shipping_name* -- the shipping name for this transaction
111
+ # * *:shipping_address* -- the shipping street address for this transaction
112
+ # * *:shipping_address2* -- the shipping street address second line (e.g., apartment, suite) for this transaction
113
+ # * *:shipping_city* -- the shipping city for this transaction
114
+ # * *:shipping_state* -- the shipping state for this transaction
115
+ # * *:shipping_postal_code* -- the shipping zip code for this transaction
116
+ # * *:shipping_region* -- the shipping region (e.g. county) for this transaction
117
+ # * *:shipping_country* -- the shipping country for this transaction
89
118
  # *:email* -- the customer's email address
90
119
  # *:customer_phone* -- the customer's phone number
91
120
  # *:customer_fax* -- the customer's fax number
@@ -94,60 +123,29 @@ module PayTrace
94
123
  # *:routing_number* -- a bank routing number to use
95
124
  # *:discretionary_data* -- discretionay data (if any) for the customer, expressed as a hash
96
125
  def self.from_cc_info(params = {})
97
- customer = Customer.new(params[:customer_id])
98
- customer.send_request(CREATE_CUSTOMER, params)
126
+ PayTrace::API::Gateway.send_request(CREATE_CUSTOMER, params, [
127
+ :customer_id,
128
+ :billing_name,
129
+ :card_number,
130
+ :expiration_month,
131
+ :expiration_year], CUSTOMER_OPTIONAL_PARAMS)
99
132
  end
100
133
 
101
134
  # See http://help.paytrace.com/api-create-customer-profile
102
- # Creates a new customer profile from credit card information. Params are the same as from_cc_info, with the exception that *:transaction_id* is used to reference a previous sale transaction instead of a credit card.
135
+ #
136
+ # Creates a new customer profile from a previous transaction.
137
+ #
138
+ # Required parameters:
139
+ #
140
+ # * *:customer_id* -- customer ID to use
141
+ # * *:billing_name* -- the billing name for this transaction
142
+ # * *:card_number* -- a credit card number
143
+ # * *:expiration_month* -- the expiration month for the credit card
144
+ # * *:expiration_year* -- the expiration year for the credit card
145
+ #
146
+ # Optional parameters are the same as *:from_cc_info*
103
147
  def self.from_transaction_id(params = {})
104
- customer = Customer.new(params[:customer_id])
105
- customer.send_request(CREATE_CUSTOMER, params)
106
- end
107
-
108
- # :nodoc:
109
- # Internal helper method; not meant to be called directly.
110
- def send_request(method, params)
111
- request ||= PayTrace::API::Request.new
112
- request.set_param(:method, method)
113
- if params[:billing_address]
114
- params[:billing_address].name = nil if (method == CREATE_CUSTOMER && params[:transaction_id])
115
- end
116
- set_request_data(params, request)
117
-
118
- gateway = PayTrace::API::Gateway.new
119
- response = gateway.send_request(request)
120
- unless response.has_errors?
121
- values = response.values
122
- @id = values["CUSTID"]
123
- @customer_id = values["CUSTOMERID"]
124
- self
125
- else
126
- nil
127
- end
128
- end
129
-
130
- # :nodoc:
131
- # Internal helper method; not meant to be called directly.
132
- def set_request_data(params, request = nil)
133
- request ||= PayTrace::API::Request.new
134
- request.set_params([
135
- :customer_id,
136
- :new_customer_id,
137
- :transaction_id,
138
- :email,
139
- [:customer_phone, :phone],
140
- [:customer_fax, :fax],
141
- :customer_password,
142
- :account_number,
143
- :routing_number
144
- ], params)
145
-
146
- params[:billing_address].set_request(request) if params[:billing_address]
147
- params[:shipping_address].set_request(request) if params[:shipping_address]
148
- params[:credit_card].set_request_data(request) if params[:credit_card]
149
-
150
- request.set_discretionary(params[:discretionary_data])
148
+ PayTrace::API::Gateway.send_request(CREATE_CUSTOMER, params, [:customer_id, :transaction_id], CUSTOMER_OPTIONAL_PARAMS)
151
149
  end
152
150
  end
153
151
  end
@@ -1,4 +1,5 @@
1
1
  require 'paytrace'
2
+ require 'minitest/autorun'
2
3
 
3
4
  module PayTrace
4
5
  # Useful helper methods for debugging.
@@ -25,6 +26,11 @@ module PayTrace
25
26
  puts ">>>>>> #{msg}"
26
27
  end
27
28
 
29
+ # split a raw request string into an array of name-value tuples
30
+ def self.split_request_string(raw)
31
+ raw.split('|').map {|kv_pair| kv_pair.split('~')}
32
+ end
33
+
28
34
  # Helper method to dump a request response pair. Usage:
29
35
  # Usage:
30
36
  # PayTrace::Debug.trace do
@@ -54,5 +60,35 @@ module PayTrace
54
60
  config.domain = domain
55
61
  end
56
62
  end
63
+
64
+ # verify whether two requests match
65
+ def self.diff_requests(expected_raw, actual_raw, case_sensitive = false)
66
+ whats_wrong = []
67
+
68
+ expected = PayTrace::Debug.split_request_string(expected_raw).map {|tuple| case_sensitive ? tuple : [tuple[0].upcase, tuple[1]]}
69
+ actual = PayTrace::Debug.split_request_string(actual_raw).map {|tuple| case_sensitive ? tuple : [tuple[0].upcase, tuple[1]]}
70
+
71
+ expected_remaining = []
72
+ actual_extra = actual.dup
73
+
74
+ expected.each do |tuple|
75
+ idx = actual_extra.find_index(tuple)
76
+ if idx.nil?
77
+ expected_remaining << tuple
78
+ else
79
+ actual_extra.delete_at(idx)
80
+ end
81
+ end
82
+
83
+ expected_remaining.each do |tuple|
84
+ whats_wrong << "Missing expected property #{tuple[0]}~#{tuple[1]}"
85
+ end
86
+
87
+ actual_extra.each do |tuple|
88
+ whats_wrong << "Extra unexpected property #{tuple[0]}~#{tuple[1]}"
89
+ end
90
+
91
+ whats_wrong
92
+ end
57
93
  end
58
94
  end
@@ -2,40 +2,16 @@ module PayTrace
2
2
  # Methods to request an email receipt for a transaction
3
3
  class EmailReceiptRequest
4
4
  # :nodoc:
5
- TRANSACTION_METHOD = "EmailReceipt"
6
- attr_accessor :email, :transaction_id, :check_id
5
+ EMAIL_RECEIPT_METHOD = "EmailReceipt"
7
6
  # :doc:
8
7
 
9
- # Initializer. Params:
8
+ # Send the request. Params:
10
9
  # *:email* -- the email address to send the receipt to
11
10
  # *:transaction_id* -- the transaction ID of the transaction to email
12
11
  # *:check_id* -- the check ID of the transaction to email
13
12
  # _Note:_ only use *:transaction_id* _or_ *:check_id* -- not both.
14
- def initialize(params = {})
15
- email, id, id_is_check_id = false
16
- @email = params[:email]
17
- @transaction_id = params[:transaction_id]
18
- @check_id = params[:check_id]
19
- end
20
-
21
- # :nodoc:
22
- def set_request(request = nil)
23
- request ||= PayTrace::API::Request.new
24
- request.set_param(:method, TRANSACTION_METHOD)
25
- request.set_param(:check_id, @check_id)
26
- request.set_param(:transaction_id, @transaction_id)
27
- request.set_param(:email, @email)
28
-
29
- request
30
- end
31
- # :doc:
32
-
33
- # Sends the request for the transaction. Accepts an existing request object, or creates one if needed.
34
- def send_request(request = nil)
35
- request ||= set_request
36
-
37
- gateway = PayTrace::API::Gateway.new
38
- gateway.send_request(request)
13
+ def self.create(params = {})
14
+ PayTrace::API::Gateway.send_request(EMAIL_RECEIPT_METHOD, params, [:email], [:check_id, :transaction_id])
39
15
  end
40
16
  end
41
17
  end
@@ -4,29 +4,25 @@ module PayTrace
4
4
  # Manages recurring transactions
5
5
  class RecurringTransaction
6
6
  # :nodoc:
7
- attr :id, :amount, :customer_id, :next, :total_count, :current_count, :repeat, :description
8
-
9
7
  CREATE_METHOD = "CreateRecur"
10
8
  DELETE_METHOD = "DeleteRecur"
11
9
  UPDATE_METHOD = "UpdateRecur"
12
10
  EXPORT_APPROVED_METHOD = "ExportCustomerRecur"
13
11
  EXPORT_SCHEDULED_METHOD = "ExportRecur"
14
12
 
15
- def initialize(raw_response)
16
- response_map = Hash[raw_response.split('+').map {|pair| pair.split('=')}]
17
- @id = response_map["RECURID"].to_i
18
- @amount = response_map["AMOUNT"].to_f
19
- @customer_id = response_map["CUSTID"]
20
- @next = response_map["NEXT"]
21
- @total_count = response_map["TOTALCOUNT"].to_i
22
- @current_count = response_map["CURRENTCOUNT"].to_i
23
- @repeat = response_map["REPEAT"].to_i
24
- @description = response_map["DESCRIPTION"]
25
- end
26
-
27
- def inspect
28
- "<RecurringTransaction:#{@id},customer id:#{@customer_id},amount: #{@amount},next: #{@next}>"
29
- end
13
+ RECURRING_TRANSACTION_PARAMS = [
14
+ :recur_id,
15
+ :customer_id,
16
+ :recur_frequency,
17
+ :recur_start,
18
+ :recur_next,
19
+ :recur_count,
20
+ :amount,
21
+ :transaction_type,
22
+ :description,
23
+ :recur_receipt,
24
+ :recur_type
25
+ ]
30
26
 
31
27
  # :doc:
32
28
 
@@ -36,14 +32,15 @@ module PayTrace
36
32
  # * *:customer_id* -- a customer ID to export
37
33
  # _Note:_ only supply a recurrence ID _or_ a customer ID, not both.
38
34
  def self.export_scheduled(params = {})
39
- parse_response(set_request_data(EXPORT_SCHEDULED_METHOD, params))
35
+ response = PayTrace::API::Gateway.send_request(EXPORT_SCHEDULED_METHOD, params, [], RECURRING_TRANSACTION_PARAMS)
36
+ response.parse_records('RECURRINGPAYMENT')
40
37
  end
41
38
 
42
39
  # See http://help.paytrace.com/api-exporting-a-recurring-transaction
43
40
  # Exports the single most recent recurring transaction for a given customer ID, Params:
44
41
  # * *:customer_id* -- the customer ID to be exported for
45
42
  def self.export_approved(params = {})
46
- set_request_data(EXPORT_APPROVED_METHOD, params)
43
+ PayTrace::API::Gateway.send_request(EXPORT_APPROVED_METHOD, params, [], RECURRING_TRANSACTION_PARAMS)
47
44
  end
48
45
 
49
46
  # See http://help.paytrace.com/api-create-recurring-transaction
@@ -58,7 +55,7 @@ module PayTrace
58
55
  # * *:recur_receipt* -- "Y" to send a receipt to the customer at each recurrence; default is "N"
59
56
  # * *:recur_type* -- default value is "C" which represents credit card number. Alternative is "A" which represents an ACH/check transaction
60
57
  def self.create(params = {})
61
- parse_response(set_request_data(CREATE_METHOD, params))
58
+ PayTrace::API::Gateway.send_request(CREATE_METHOD, params, [], RECURRING_TRANSACTION_PARAMS)
62
59
  end
63
60
 
64
61
  # See http://help.paytrace.com/api-deleting-a-recurring-transaction
@@ -67,16 +64,8 @@ module PayTrace
67
64
  # * *:customer_id* -- a customer ID to export
68
65
  # _Note:_ only supply a recurrence ID _or_ a customer ID, not both.
69
66
  def self.delete(params = {})
70
- request = PayTrace::API::Request.new
71
- request.set_param(:method, DELETE_METHOD)
72
- if params[:recur_id]
73
- request.set_param(:recur_id, params[:recur_id])
74
- else
75
- request.set_param(:customer_id, params[:customer_id])
76
- end
77
-
78
- gateway = PayTrace::API::Gateway.new
79
- parse_response(gateway.send_request(request))
67
+ fields = params.has_key?(:recur_id) ? [:recur_id] : [:customer_id]
68
+ response = PayTrace::API::Gateway.send_request(DELETE_METHOD, params, [], fields)
80
69
  end
81
70
 
82
71
  # See http://help.paytrace.com/api-update-recurring-transaction
@@ -92,43 +81,7 @@ module PayTrace
92
81
  # * *:recur_receipt* -- "Y" to send a receipt to the customer at each recurrence; default is "N"
93
82
  # * *:recur_type* -- default value is "C" which represents credit card number. Alternative is "A" which represents an ACH/check transaction; _note:_ only use for check/ACH recurrences
94
83
  def self.update(params = {})
95
- parse_response(set_request_data(UPDATE_METHOD, params))
96
- end
97
-
98
- # :nodoc:
99
- def self.parse_response(response)
100
- unless response.has_errors?
101
- values = response.values
102
-
103
- if values.has_key?("RECURRINGPAYMENT")
104
- new(values["RECURRINGPAYMENT"])
105
- else
106
- values["RECURID"]
107
- end
108
- end
84
+ PayTrace::API::Gateway.send_request(UPDATE_METHOD, params, [], RECURRING_TRANSACTION_PARAMS)
109
85
  end
110
-
111
- def self.set_request_data(method, params)
112
- request = PayTrace::API::Request.new
113
- request.set_param(:method, method)
114
-
115
- request.set_params([
116
- :recur_id,
117
- :customer_id,
118
- :recur_frequency,
119
- :recur_start,
120
- :recur_next,
121
- :recur_count,
122
- :amount,
123
- :transaction_type,
124
- :description,
125
- :recur_receipt,
126
- :recur_type
127
- ], params)
128
-
129
- gateway = PayTrace::API::Gateway.new
130
- gateway.send_request(request)
131
- end
132
- # :doc:
133
86
  end
134
87
  end