paytrace 0.1.23 → 1.0.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 (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