payload-api 0.4.1 → 0.6.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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -0
- data/LICENSE +1 -1
- data/README.md +23 -2
- data/lib/payload/arm/attr.rb +169 -0
- data/lib/payload/arm/object.rb +44 -1
- data/lib/payload/arm/request.rb +66 -6
- data/lib/payload/arm/session.rb +13 -9
- data/lib/payload/exceptions.rb +15 -0
- data/lib/payload/objects.rb +81 -18
- data/lib/payload/version.rb +2 -2
- data/lib/payload.rb +15 -5
- data/spec/objects/v1/access_token_spec.rb +19 -0
- data/spec/objects/v1/account_spec.rb +97 -0
- data/spec/objects/v1/billing_spec.rb +54 -0
- data/spec/objects/v1/invoice_spec.rb +53 -0
- data/spec/objects/v1/payment_link_spec.rb +50 -0
- data/spec/objects/v1/payment_method_spec.rb +106 -0
- data/spec/objects/{payment_spec.rb → v1/payment_spec.rb} +5 -6
- data/spec/objects/v1/session_spec.rb +89 -0
- data/spec/objects/v1/transaction_spec.rb +55 -0
- data/spec/objects/v2/account_spec.rb +211 -0
- data/spec/objects/v2/invoice_spec.rb +53 -0
- data/spec/objects/v2/payment_method_spec.rb +106 -0
- data/spec/objects/v2/transaction_spec.rb +48 -0
- data/spec/payload/arm/arm_request_query_spec.rb +226 -0
- data/spec/payload/arm/attr_spec.rb +216 -0
- data/spec/payload/arm/object_spec.rb +114 -0
- data/spec/payload/arm/request_format_integration_spec.rb +166 -0
- data/spec/payload/arm/request_spec.rb +259 -1
- data/spec/payload/arm/session_spec.rb +40 -0
- data/spec/payload/exceptions_spec.rb +82 -0
- data/spec/support/helpers/v1_helpers.rb +159 -0
- data/spec/support/helpers/v2_helpers.rb +205 -0
- data/spec/support/helpers.rb +15 -0
- data/spec/support/helpers_spec.rb +21 -0
- metadata +28 -6
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
require 'payload'
|
|
2
|
+
require 'payload/arm/object'
|
|
3
|
+
require_relative '../../support/helpers'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'Account Integration Tests - V2' do
|
|
6
|
+
include_context 'test helpers'
|
|
7
|
+
|
|
8
|
+
let(:session) { Payload::Session.new(Payload.api_key, Payload.api_url, 2) }
|
|
9
|
+
|
|
10
|
+
describe 'Customer Account' do
|
|
11
|
+
it 'creates a customer account' do
|
|
12
|
+
customer_account = session.Account.create(
|
|
13
|
+
type: 'customer',
|
|
14
|
+
name: 'Test',
|
|
15
|
+
contact_details: {
|
|
16
|
+
email: 'test@example.com'
|
|
17
|
+
}
|
|
18
|
+
)
|
|
19
|
+
expect(customer_account.id).to be_truthy
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'deletes a customer account' do
|
|
23
|
+
cust_account = session.Account.create(
|
|
24
|
+
type: 'customer',
|
|
25
|
+
name: 'Test',
|
|
26
|
+
contact_details: {
|
|
27
|
+
email: 'test@example.com'
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
cust_account.delete
|
|
31
|
+
|
|
32
|
+
expect {
|
|
33
|
+
session.Account.get(cust_account.id)
|
|
34
|
+
}.to raise_error(Payload::NotFound)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'creates multiple accounts' do
|
|
38
|
+
rand_email1 = (0...5).map { ('a'..'z').to_a[rand(26)] }.join + '@example.com'
|
|
39
|
+
rand_email2 = (0...5).map { ('a'..'z').to_a[rand(26)] }.join + '@example.com'
|
|
40
|
+
|
|
41
|
+
name1 = 'Matt Perez'
|
|
42
|
+
name2 = 'Andrea Kearney'
|
|
43
|
+
|
|
44
|
+
accounts_to_create = [
|
|
45
|
+
session.Account.new(type: 'customer', contact_details: { email: rand_email1 }, name: name1),
|
|
46
|
+
session.Account.new(type: 'customer', contact_details: { email: rand_email2 }, name: name2)
|
|
47
|
+
]
|
|
48
|
+
session.create(accounts_to_create)
|
|
49
|
+
|
|
50
|
+
get_account_1 = session.Account.filter_by(type: 'customer', 'contact_details[email]': rand_email1).all[0]
|
|
51
|
+
get_account_2 = session.Account.filter_by(type: 'customer', 'contact_details[email]': rand_email2).all[0]
|
|
52
|
+
|
|
53
|
+
expect(get_account_1).to be_truthy
|
|
54
|
+
expect(get_account_2).to be_truthy
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'gets a processing account' do
|
|
58
|
+
orgs = session.Profile.all()
|
|
59
|
+
org = orgs[0]
|
|
60
|
+
proc_account = session.Account.create(
|
|
61
|
+
type: 'processing',
|
|
62
|
+
name: 'Processing Account',
|
|
63
|
+
processing: {
|
|
64
|
+
status: { funding: 'pending' },
|
|
65
|
+
settings_id: org.processing_settings_id,
|
|
66
|
+
},
|
|
67
|
+
payment_methods: [session.PaymentMethod.new(
|
|
68
|
+
type: 'bank_account',
|
|
69
|
+
bank_account: {
|
|
70
|
+
account_number: '123456789',
|
|
71
|
+
routing_number: '036001808',
|
|
72
|
+
account_type: 'checking'
|
|
73
|
+
},
|
|
74
|
+
billing_address: {
|
|
75
|
+
postal_code: '11111',
|
|
76
|
+
},
|
|
77
|
+
account_defaults: {
|
|
78
|
+
funding: 'all',
|
|
79
|
+
}
|
|
80
|
+
)],
|
|
81
|
+
entity: {
|
|
82
|
+
type: 'business',
|
|
83
|
+
legal_name: 'Example',
|
|
84
|
+
country: 'US',
|
|
85
|
+
phone_number: '123 123-1234',
|
|
86
|
+
tax_id: { value: '123 12 1234' },
|
|
87
|
+
address: {
|
|
88
|
+
address_line_1: '123 Example St',
|
|
89
|
+
city: 'New York',
|
|
90
|
+
state_province: 'NY',
|
|
91
|
+
postal_code: '11111',
|
|
92
|
+
},
|
|
93
|
+
business: {
|
|
94
|
+
category: 'real_estate',
|
|
95
|
+
structure: 'llc',
|
|
96
|
+
website: 'https://example.com',
|
|
97
|
+
formation: {
|
|
98
|
+
state_province: 'NY',
|
|
99
|
+
date: '2019-10-01',
|
|
100
|
+
},
|
|
101
|
+
primary_contact: {
|
|
102
|
+
name: 'John Smith',
|
|
103
|
+
email: 'johnsmith@gmail.com',
|
|
104
|
+
},
|
|
105
|
+
stakeholders: [
|
|
106
|
+
{
|
|
107
|
+
country: 'US',
|
|
108
|
+
personal_information: {
|
|
109
|
+
full_name: 'John Smith',
|
|
110
|
+
email: 'johnsmith@gmail.com',
|
|
111
|
+
birth_date: '1990-05-10',
|
|
112
|
+
phone_number: '123 123-1234',
|
|
113
|
+
},
|
|
114
|
+
address: {
|
|
115
|
+
address_line_1: '123 Example St',
|
|
116
|
+
city: 'New York',
|
|
117
|
+
state_province: 'NY',
|
|
118
|
+
postal_code: '11111',
|
|
119
|
+
},
|
|
120
|
+
govt_id: {
|
|
121
|
+
tax_id: { value: '123 12 1234' },
|
|
122
|
+
},
|
|
123
|
+
association: {
|
|
124
|
+
roles: ['principal_officer'],
|
|
125
|
+
title: 'CEO',
|
|
126
|
+
ownership: {
|
|
127
|
+
percentage: 100,
|
|
128
|
+
years_owned: 5,
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
)
|
|
136
|
+
retrieved = session.Account.get(proc_account.id)
|
|
137
|
+
expect(retrieved).to be_truthy
|
|
138
|
+
expect(proc_account.processing['status']['funding']).to eq('pending')
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it 'pages and orders results' do
|
|
142
|
+
accounts_to_create = [
|
|
143
|
+
session.Account.new(type: 'customer', contact_details: { email: 'account1@example.com' }, name: 'Randy Robson'),
|
|
144
|
+
session.Account.new(type: 'customer', contact_details: { email: 'account2@example.com' }, name: 'Brandy Bobson'),
|
|
145
|
+
session.Account.new(type: 'customer', contact_details: { email: 'account3@example.com' }, name: 'Mandy Johnson')
|
|
146
|
+
]
|
|
147
|
+
session.create(accounts_to_create)
|
|
148
|
+
customers = session.Account.filter_by(type: 'customer', order_by: 'created_at', limit: 3, offset: 1).all
|
|
149
|
+
|
|
150
|
+
expect(customers.length).to eq(3)
|
|
151
|
+
require 'time'
|
|
152
|
+
expect(Time.parse(customers[0].created_at)).to be <= Time.parse(customers[1].created_at)
|
|
153
|
+
expect(Time.parse(customers[1].created_at)).to be <= Time.parse(customers[2].created_at)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'updates a customer' do
|
|
157
|
+
cust_account = session.Account.create(
|
|
158
|
+
type: 'customer',
|
|
159
|
+
name: 'Test',
|
|
160
|
+
contact_details: {
|
|
161
|
+
email: 'test@example.com'
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
cust_account.update(contact_details: { email: 'test2@example.com' })
|
|
165
|
+
expect(cust_account.contact_details['email']).to eq('test2@example.com')
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it 'updates multiple accounts' do
|
|
169
|
+
customer_account_1 = session.Account.create(
|
|
170
|
+
type: 'customer',
|
|
171
|
+
name: 'Brandy',
|
|
172
|
+
contact_details: { email: 'test1@example.com' }
|
|
173
|
+
)
|
|
174
|
+
customer_account_2 = session.Account.create(
|
|
175
|
+
type: 'customer',
|
|
176
|
+
name: 'Sandy',
|
|
177
|
+
contact_details: { email: 'test2@example.com' }
|
|
178
|
+
)
|
|
179
|
+
updated_accounts = session.update([
|
|
180
|
+
[customer_account_1, { contact_details: { email: 'brandy@example.com' } }],
|
|
181
|
+
[customer_account_2, { contact_details: { email: 'sandy@example.com' } }]
|
|
182
|
+
])
|
|
183
|
+
|
|
184
|
+
expect(updated_accounts[0].contact_details['email']).to eq('brandy@example.com')
|
|
185
|
+
expect(updated_accounts[1].contact_details['email']).to eq('sandy@example.com')
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it 'gets a customer' do
|
|
189
|
+
cust_account = session.Account.create(
|
|
190
|
+
type: 'customer',
|
|
191
|
+
name: 'Test',
|
|
192
|
+
contact_details: {
|
|
193
|
+
email: 'test@example.com'
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
expect(session.Account.get(cust_account.id)).to be_truthy
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it 'selects customer attributes' do
|
|
200
|
+
cust_account = session.Account.create(
|
|
201
|
+
type: 'customer',
|
|
202
|
+
name: 'Test',
|
|
203
|
+
contact_details: {
|
|
204
|
+
email: 'test@example.com'
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
selected = session.Account.select('id').get(cust_account.id)
|
|
208
|
+
expect(selected['id']).to eq(cust_account.id)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'payload'
|
|
2
|
+
require 'payload/arm/object'
|
|
3
|
+
require 'date'
|
|
4
|
+
require_relative '../../support/helpers'
|
|
5
|
+
|
|
6
|
+
RSpec.describe 'Invoice Integration Tests - V2' do
|
|
7
|
+
include_context 'test helpers'
|
|
8
|
+
|
|
9
|
+
let(:session) { Payload::Session.new(Payload.api_key, Payload.api_url, 2) }
|
|
10
|
+
let(:h) { V2Helpers.new(session) }
|
|
11
|
+
|
|
12
|
+
let(:proc_account) { h.create_processing_account }
|
|
13
|
+
let(:customer_account) { h.create_customer_account }
|
|
14
|
+
let(:invoice) { h.create_invoice(proc_account, customer_account) }
|
|
15
|
+
|
|
16
|
+
describe 'Invoice' do
|
|
17
|
+
it 'creates an invoice' do
|
|
18
|
+
inv = invoice
|
|
19
|
+
expect(inv.due_date).to eq(Date.today.strftime('%Y-%m-%d'))
|
|
20
|
+
expect(inv.status).to eq('unpaid')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'pays an invoice' do
|
|
24
|
+
inv = invoice
|
|
25
|
+
expect(inv.due_date).to eq(Date.today.strftime('%Y-%m-%d'))
|
|
26
|
+
expect(inv.status).to eq('unpaid')
|
|
27
|
+
|
|
28
|
+
amount = inv.totals['balance_due']
|
|
29
|
+
|
|
30
|
+
if inv.status != 'paid'
|
|
31
|
+
h.create_card_payment(
|
|
32
|
+
proc_account.id,
|
|
33
|
+
amount: amount,
|
|
34
|
+
description: 'Test Payment',
|
|
35
|
+
customer_id: customer_account.id,
|
|
36
|
+
invoice_id: inv.id
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
get_invoice = session.Invoice.get(inv.id)
|
|
41
|
+
expect(get_invoice.status).to eq('paid')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'deletes an invoice' do
|
|
45
|
+
inv = invoice
|
|
46
|
+
inv.delete
|
|
47
|
+
|
|
48
|
+
expect {
|
|
49
|
+
session.Invoice.get(inv.id)
|
|
50
|
+
}.to raise_error(Payload::NotFound)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'payload'
|
|
2
|
+
require 'payload/arm/object'
|
|
3
|
+
require_relative '../../support/helpers'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'Payment Method Integration Tests - V2' do
|
|
6
|
+
include_context 'test helpers'
|
|
7
|
+
|
|
8
|
+
let(:session) { Payload::Session.new(Payload.api_key, Payload.api_url, 2) }
|
|
9
|
+
let(:h) { V2Helpers.new(session) }
|
|
10
|
+
let(:proc_account) { h.create_processing_account }
|
|
11
|
+
|
|
12
|
+
describe 'Payment Methods' do
|
|
13
|
+
it 'creates a payment with card' do
|
|
14
|
+
card_payment = h.create_card_payment(proc_account.id)
|
|
15
|
+
expect(card_payment.status['value']).to eq('processed')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'creates a payment with bank account' do
|
|
19
|
+
bank_payment = h.create_bank_payment
|
|
20
|
+
expect(bank_payment.status['value']).to eq('processed')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'filters payments' do
|
|
24
|
+
rand_description = (0...10).map { ('a'..'z').to_a[rand(26)] }.join
|
|
25
|
+
|
|
26
|
+
amounts = [90.0, 100.0, 110.0]
|
|
27
|
+
card_payments = []
|
|
28
|
+
amounts.each do |amount|
|
|
29
|
+
card_payment = h.create_card_payment(proc_account.id, amount: amount, description: rand_description)
|
|
30
|
+
card_payments << card_payment
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
payments = session.Transaction.filter_by(
|
|
34
|
+
type: 'payment',
|
|
35
|
+
amount: '100',
|
|
36
|
+
description: rand_description
|
|
37
|
+
).all
|
|
38
|
+
|
|
39
|
+
expect(payments.length).to be == 1
|
|
40
|
+
expect(payments.map(&:id)).to include(card_payments[1].id)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'voids a card payment' do
|
|
44
|
+
card_payment = h.create_card_payment(proc_account.id)
|
|
45
|
+
card_payment.update(status: { value: 'voided' })
|
|
46
|
+
expect(card_payment.status['value']).to eq('voided')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'voids a bank payment' do
|
|
50
|
+
bank_payment = h.create_bank_payment
|
|
51
|
+
bank_payment.update(status: { value: 'voided' })
|
|
52
|
+
expect(bank_payment.status['value']).to eq('voided')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'refunds a card payment' do
|
|
56
|
+
card_payment = h.create_card_payment(proc_account.id)
|
|
57
|
+
refund = h.create_refund(card_payment)
|
|
58
|
+
|
|
59
|
+
expect(refund.type).to eq('refund')
|
|
60
|
+
expect(refund.amount).to eq(card_payment.amount)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'partially refunds a card payment' do
|
|
64
|
+
card_payment = h.create_card_payment(proc_account.id)
|
|
65
|
+
amount = (card_payment.amount/2).round(2) # rounded to 2 decimal places
|
|
66
|
+
refund = h.create_refund(card_payment, amount: amount)
|
|
67
|
+
|
|
68
|
+
expect(refund.type).to eq('refund')
|
|
69
|
+
expect(refund.amount).to eq(amount)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'creates a blind refund for card payment' do
|
|
73
|
+
refund = h.create_blind_refund(10, proc_account.id)
|
|
74
|
+
|
|
75
|
+
expect(refund.type).to eq('refund')
|
|
76
|
+
expect(refund.amount).to eq(10)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'refunds a bank payment' do
|
|
80
|
+
bank_payment = h.create_bank_payment
|
|
81
|
+
refund = h.create_refund(bank_payment)
|
|
82
|
+
|
|
83
|
+
expect(refund.type).to eq('refund')
|
|
84
|
+
expect(refund.amount).to eq(bank_payment.amount)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'partially refunds a bank payment' do
|
|
88
|
+
bank_payment = h.create_bank_payment
|
|
89
|
+
amount = (bank_payment.amount/2).round(2) # rounded to 2 decimal places
|
|
90
|
+
refund = h.create_refund(bank_payment, amount: amount)
|
|
91
|
+
|
|
92
|
+
expect(refund.type).to eq('refund')
|
|
93
|
+
expect(refund.amount).to eq(amount)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'raises error for invalid payment method type' do
|
|
97
|
+
expect {
|
|
98
|
+
session.Transaction.create(
|
|
99
|
+
type: 'invalid',
|
|
100
|
+
card_number: '4242 4242 4242 4242',
|
|
101
|
+
expiry: '12/30'
|
|
102
|
+
)
|
|
103
|
+
}.to raise_error(Payload::InvalidAttributes)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'payload'
|
|
2
|
+
require 'payload/arm/object'
|
|
3
|
+
require_relative '../../support/helpers'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'Transaction Integration Tests - V2' do
|
|
6
|
+
include_context 'test helpers'
|
|
7
|
+
|
|
8
|
+
let(:session) { Payload::Session.new(Payload.api_key, Payload.api_url, 2) }
|
|
9
|
+
let(:h) { V2Helpers.new(session) }
|
|
10
|
+
let(:proc_account) { h.create_processing_account }
|
|
11
|
+
|
|
12
|
+
describe 'Transactions' do
|
|
13
|
+
|
|
14
|
+
it 'has empty transaction ledger' do
|
|
15
|
+
card_payment = h.create_card_payment(proc_account.id)
|
|
16
|
+
transaction = session.Transaction.select('*', 'ledger').get(card_payment.id)
|
|
17
|
+
expect(transaction.ledger).to eq([])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'tests unified payout batching' do
|
|
21
|
+
h.create_blind_refund(10, proc_account.id)
|
|
22
|
+
|
|
23
|
+
transactions = session.Transaction.select('*', 'ledger')
|
|
24
|
+
.filter_by(type: 'refund', processing_id: proc_account.id)
|
|
25
|
+
.all
|
|
26
|
+
|
|
27
|
+
expect(transactions.length).to eq(1)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'gets transactions' do
|
|
31
|
+
h.create_card_payment(proc_account.id)
|
|
32
|
+
payments = session.Transaction.filter_by('status[value]': 'processed', type: 'payment', 'receiver[account_id]': proc_account.id).all
|
|
33
|
+
expect(payments.length).to be > 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'updates processed transaction' do
|
|
37
|
+
card_payment = h.create_card_payment(proc_account.id)
|
|
38
|
+
card_payment.update(status: { value: 'voided' })
|
|
39
|
+
expect(card_payment.status['value']).to eq('voided')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'raises error for transaction not found' do
|
|
43
|
+
expect {
|
|
44
|
+
session.Transaction.get('invalid')
|
|
45
|
+
}.to raise_error(Payload::NotFound)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "payload"
|
|
4
|
+
require "payload/arm/object"
|
|
5
|
+
|
|
6
|
+
RSpec.describe Payload::ARMRequest do
|
|
7
|
+
describe "#group_by" do
|
|
8
|
+
let(:instance) { described_class.new(Payload::Invoice, nil) }
|
|
9
|
+
|
|
10
|
+
it "appends to group_by and returns self" do
|
|
11
|
+
year_attr = Payload::Attr.new("year", Payload::Attr.new("created_at"))
|
|
12
|
+
year_attr.call
|
|
13
|
+
result = instance.group_by(year_attr, Payload::Attr.status)
|
|
14
|
+
expect(result).to be(instance)
|
|
15
|
+
expect(instance.instance_variable_get(:@group_by).map(&:to_s)).to eq(["year(created_at)", "status"])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "includes group_by in request params when all() is called" do
|
|
19
|
+
Payload::api_key = "test_key"
|
|
20
|
+
instance.instance_variable_set(:@cls, Payload::Invoice)
|
|
21
|
+
|
|
22
|
+
expect(instance).to receive(:_execute_request) do |_http, request|
|
|
23
|
+
query = request.path.split("?")[1]
|
|
24
|
+
expect(query).to include("group_by%5B0%5D=") # group_by[0]=
|
|
25
|
+
expect(query).to include("group_by%5B1%5D=") # group_by[1]=
|
|
26
|
+
QuerySpecMockResponse.new('{"object":"list","values":[]}')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
instance.group_by("year(created_at)", "status").all()
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#order_by" do
|
|
34
|
+
let(:instance) { described_class.new(Payload::Account, nil) }
|
|
35
|
+
|
|
36
|
+
it "appends to order_by and returns self" do
|
|
37
|
+
result = instance.order_by("created_at", "desc(id)")
|
|
38
|
+
expect(result).to be(instance)
|
|
39
|
+
expect(instance.instance_variable_get(:@order_by)).to eq(["created_at", "desc(id)"])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "includes order_by in request params when all() is called" do
|
|
43
|
+
Payload::api_key = "test_key"
|
|
44
|
+
instance.instance_variable_set(:@cls, Payload::Account)
|
|
45
|
+
|
|
46
|
+
expect(instance).to receive(:_execute_request) do |_http, request|
|
|
47
|
+
query = request.path.split("?")[1]
|
|
48
|
+
expect(query).to include("order_by%5B0%5D=created_at")
|
|
49
|
+
expect(query).to include("order_by%5B1%5D=desc%28id%29")
|
|
50
|
+
QuerySpecMockResponse.new('{"object":"list","values":[]}')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
instance.order_by("created_at", "desc(id)").all()
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe "#limit and #offset" do
|
|
58
|
+
let(:instance) { described_class.new(Payload::Account, nil) }
|
|
59
|
+
|
|
60
|
+
it "sets limit and offset and returns self" do
|
|
61
|
+
result = instance.limit(10).offset(20)
|
|
62
|
+
expect(result).to be(instance)
|
|
63
|
+
expect(instance.instance_variable_get(:@limit)).to eq(10)
|
|
64
|
+
expect(instance.instance_variable_get(:@offset)).to eq(20)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "includes limit and offset in request params when all() is called" do
|
|
68
|
+
Payload::api_key = "test_key"
|
|
69
|
+
instance.instance_variable_set(:@cls, Payload::Account)
|
|
70
|
+
|
|
71
|
+
expect(instance).to receive(:_execute_request) do |_http, request|
|
|
72
|
+
query = request.path.split("?")[1]
|
|
73
|
+
expect(query).to include("limit=10")
|
|
74
|
+
expect(query).to include("offset=20")
|
|
75
|
+
QuerySpecMockResponse.new('{"object":"list","values":[]}')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
instance.limit(10).offset(20).all()
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe "#request_params" do
|
|
83
|
+
it "merges filters, filter_objects, group_by, order_by, limit, offset into query params" do
|
|
84
|
+
instance = described_class.new(Payload::Transaction, nil)
|
|
85
|
+
instance.instance_variable_set(:@filters, { "fields" => "id,amount" })
|
|
86
|
+
instance.instance_variable_set(:@group_by, ["status"])
|
|
87
|
+
instance.instance_variable_set(:@order_by, ["desc(created_at)"])
|
|
88
|
+
instance.instance_variable_set(:@limit, 5)
|
|
89
|
+
instance.instance_variable_set(:@offset, 10)
|
|
90
|
+
|
|
91
|
+
filter_obj = Payload::ARMGreaterThan.new(Payload::Attr.amount, 100)
|
|
92
|
+
instance.instance_variable_set(:@filter_objects, [filter_obj])
|
|
93
|
+
|
|
94
|
+
params = instance.request_params
|
|
95
|
+
|
|
96
|
+
expect(params["fields"]).to eq("id,amount")
|
|
97
|
+
expect(params["group_by[0]"]).to eq("status")
|
|
98
|
+
expect(params["order_by[0]"]).to eq("desc(created_at)")
|
|
99
|
+
expect(params["limit"]).to eq("5")
|
|
100
|
+
expect(params["offset"]).to eq("10")
|
|
101
|
+
expect(params[filter_obj.attr]).to eq(filter_obj.opval)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "is encoded as URL query string in _request (url.query = URI.encode_www_form(params))" do
|
|
105
|
+
Payload::api_key = "test_key"
|
|
106
|
+
session = Payload::Session.new("test_key", "https://api.test.com", "v2")
|
|
107
|
+
instance = described_class.new(Payload::Invoice, session)
|
|
108
|
+
instance.select("id", "status").filter_by(session.attr.status == "open").order_by("created_at").limit(5).offset(1)
|
|
109
|
+
|
|
110
|
+
expected_params = instance.request_params.dup
|
|
111
|
+
|
|
112
|
+
expect(instance).to receive(:_execute_request) do |_http, request|
|
|
113
|
+
query_str = request.path.split("?", 2)[1]
|
|
114
|
+
expect(query_str).not_to be_nil
|
|
115
|
+
decoded = URI.decode_www_form(query_str || "").to_h
|
|
116
|
+
expected_params.each do |key, value|
|
|
117
|
+
expect(decoded[key]).to eq(value.to_s)
|
|
118
|
+
end
|
|
119
|
+
expect(decoded).to include("fields" => "id,status", "limit" => "5", "offset" => "1")
|
|
120
|
+
expect(decoded.keys).to include("status", "order_by[0]")
|
|
121
|
+
QuerySpecMockResponse.new('{"object":"list","values":[]}')
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
instance.all()
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe "#[] (slice)" do
|
|
129
|
+
let(:instance) { described_class.new(Payload::Account, nil) }
|
|
130
|
+
|
|
131
|
+
it "raises TypeError for non-Range key" do
|
|
132
|
+
expect { instance["foo"] }.to raise_error(TypeError, /invalid key or index/)
|
|
133
|
+
expect { instance[5] }.to raise_error(TypeError, /invalid key or index/)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "raises ArgumentError for negative begin" do
|
|
137
|
+
expect { instance[-1..10] }.to raise_error(ArgumentError, /Negative slice indices not supported/)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "raises ArgumentError for negative end" do
|
|
141
|
+
expect { instance[0..-5] }.to raise_error(ArgumentError, /Negative slice indices not supported/)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "calls offset(begin).limit(size).all() for a range and returns result" do
|
|
145
|
+
Payload::api_key = "test_key"
|
|
146
|
+
instance.instance_variable_set(:@cls, Payload::Account)
|
|
147
|
+
|
|
148
|
+
expect(instance).to receive(:_execute_request) do |_http, request|
|
|
149
|
+
query = request.path.split("?")[1]
|
|
150
|
+
expect(query).to include("offset=10")
|
|
151
|
+
expect(query).to include("limit=10")
|
|
152
|
+
QuerySpecMockResponse.new('{"object":"list","values":[{"id":"acct_1","object":"customer"}]}')
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
result = instance[10..19]
|
|
156
|
+
expect(result).to be_an(Array)
|
|
157
|
+
expect(result.size).to eq(1)
|
|
158
|
+
expect(result[0].id).to eq("acct_1")
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
describe "#filter_by with pl.attr filter objects" do
|
|
163
|
+
it "extracts ARM filter objects and merges their attr/opval into request params" do
|
|
164
|
+
session = Payload::Session.new("test_key", "https://api.test.com", "v2")
|
|
165
|
+
instance = described_class.new(Payload::Transaction, session)
|
|
166
|
+
pl = session
|
|
167
|
+
filter_expr = (pl.attr.amount > 100) | (pl.attr.amount < 200)
|
|
168
|
+
|
|
169
|
+
instance.filter_by(filter_expr)
|
|
170
|
+
|
|
171
|
+
expect(instance.instance_variable_get(:@filter_objects)).to include(be_a(Payload::ARMFilter))
|
|
172
|
+
params = instance.request_params
|
|
173
|
+
expect(params.keys).to include(filter_expr.attr)
|
|
174
|
+
expect(params[filter_expr.attr]).to eq(filter_expr.opval)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "builds GET request with filter object serialized in query string" do
|
|
178
|
+
Payload::api_key = "test_key"
|
|
179
|
+
session = Payload::Session.new("test_key", "https://api.test.com", "v2")
|
|
180
|
+
instance = described_class.new(Payload::Transaction, session)
|
|
181
|
+
filter_expr = session.attr.amount > 100
|
|
182
|
+
|
|
183
|
+
instance.filter_by(filter_expr)
|
|
184
|
+
|
|
185
|
+
expect(instance).to receive(:_execute_request) do |_http, request|
|
|
186
|
+
query = request.path.split("?")[1]
|
|
187
|
+
expect(query).to include("amount=")
|
|
188
|
+
expect(query).to include("%3E100") # URL-encoded ">100"
|
|
189
|
+
QuerySpecMockResponse.new('{"object":"list","values":[]}')
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
instance.all()
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
describe "#filter_by with multiple filters" do
|
|
197
|
+
it "accumulates multiple filter objects and merges keyword filters into @filters" do
|
|
198
|
+
instance = described_class.new(Payload::Invoice, nil)
|
|
199
|
+
f1 = Payload::ARMEqual.new(Payload::Attr.status, "open")
|
|
200
|
+
f2 = Payload::ARMGreaterThan.new(Payload::Attr.amount, 50)
|
|
201
|
+
|
|
202
|
+
instance.filter_by(f1).filter_by(f2).filter_by(custom_key: "value")
|
|
203
|
+
|
|
204
|
+
fo = instance.instance_variable_get(:@filter_objects)
|
|
205
|
+
expect(fo).to include(f1, f2)
|
|
206
|
+
params = instance.request_params
|
|
207
|
+
expect(params["status"]).to eq("open")
|
|
208
|
+
expect(params["amount"]).to eq(">50")
|
|
209
|
+
expect(instance.instance_variable_get(:@filters)[:custom_key]).to eq("value")
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
class QuerySpecMockResponse
|
|
215
|
+
def initialize(body = '{"object":"list","values":[]}')
|
|
216
|
+
@body = body
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def code
|
|
220
|
+
"200"
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def body
|
|
224
|
+
@body
|
|
225
|
+
end
|
|
226
|
+
end
|