perka 1.1 → 1.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.
- data/Rakefile +14 -13
- data/lib/perka/model/merchant_location.rb +30 -25
- data/lib/perka/version.rb +1 -1
- data/spec/api_integrator_spec.rb +116 -93
- metadata +4 -4
data/Rakefile
CHANGED
@@ -8,7 +8,8 @@ FLATPACK_OUTPUT_DIR = "#{OUTPUT_DIR}/generated"
|
|
8
8
|
GEM_OUTPUT_DIR = "#{OUTPUT_DIR}/gem"
|
9
9
|
|
10
10
|
# Defalt to the most recently released version. Use LATEST for bleeding-edge.
|
11
|
-
FAST_VERSION = 'RELEASE'
|
11
|
+
#FAST_VERSION = 'RELEASE'
|
12
|
+
FAST_VERSION = '2.16-SNAPSHOT'
|
12
13
|
FAST_JAR = "#{OUTPUT_DIR}/fast.jar"
|
13
14
|
|
14
15
|
task :clean do
|
@@ -18,33 +19,33 @@ end
|
|
18
19
|
|
19
20
|
desc "Generates the flatpack lib"
|
20
21
|
task :gen do
|
21
|
-
|
22
|
+
|
22
23
|
# download the fast executable jar if we haven't already
|
23
24
|
unless(File.exist?("#{FAST_JAR}"))
|
24
25
|
puts 'fetching fast.jar...'
|
25
|
-
|
26
|
+
|
26
27
|
`mvn -f ../flatpack-java/fast/pom.xml install`
|
27
28
|
|
28
29
|
`mvn -U org.apache.maven.plugins:maven-dependency-plugin:2.4:get \
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
-Drepo=https://oss.sonatype.org/content/groups/public/ \
|
31
|
+
-Dartifact=com.getperka.flatpack:flatpack-fast:#{FAST_VERSION}:jar:shaded \
|
32
|
+
-Ddest=#{FAST_JAR}`
|
32
33
|
end
|
33
34
|
|
34
35
|
puts 'running fast code generation...'
|
35
36
|
puts `java -jar #{FAST_JAR} \
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
--RbDialect.gemName perka \
|
38
|
+
--RbDialect.moduleName Perka \
|
39
|
+
--RbDialect.modelModuleName Model \
|
40
|
+
generate --in #{API_SRC} --dialect rb --out #{OUTPUT_DIR} $@`
|
40
41
|
end
|
41
42
|
|
42
43
|
desc "Combines the generated flatpack code with our local code in the gem output dir"
|
43
44
|
task :combine => :gen do
|
44
|
-
# clean up
|
45
|
+
# clean up
|
45
46
|
`rm -rf #{GEM_OUTPUT_DIR}`
|
46
47
|
`mkdir -p #{GEM_OUTPUT_DIR}`
|
47
|
-
|
48
|
+
|
48
49
|
# combine our code in the gem output dir
|
49
50
|
`cp -r #{SRC_DIR}/* #{GEM_OUTPUT_DIR}`
|
50
51
|
`cp -r #{FLATPACK_OUTPUT_DIR}/* #{GEM_OUTPUT_DIR}/lib`
|
@@ -67,4 +68,4 @@ end
|
|
67
68
|
desc "Install Gem"
|
68
69
|
task :install => :test do
|
69
70
|
Dir.chdir(GEM_OUTPUT_DIR) { puts `bundle install` }
|
70
|
-
end
|
71
|
+
end
|
@@ -3,42 +3,47 @@
|
|
3
3
|
require 'perka/model/base_entity_global'
|
4
4
|
|
5
5
|
module Perka
|
6
|
-
module Model
|
6
|
+
module Model
|
7
7
|
|
8
|
-
# Represents a single physical location operated by a Merchant where Customers
|
8
|
+
# Represents a single physical location operated by a Merchant where Customers
|
9
9
|
# can participate in a Perka loyalty program.
|
10
10
|
class MerchantLocation < BaseEntityGlobal
|
11
11
|
|
12
12
|
PROPERTY_NAMES = [
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
13
|
+
:phone,
|
14
|
+
:merchant,
|
15
|
+
:timezone,
|
16
|
+
|
17
|
+
# The named Clerks which are allowed to operate on the MerchantLocation.
|
18
|
+
# This relationship is owned by the Clerk object.
|
19
|
+
:clerks,
|
20
|
+
|
21
|
+
# Used to implicitly concatenate the <code>address</code> and <code>address2</code>
|
22
|
+
# fields in a friendly format.
|
23
|
+
:combined_address,
|
24
|
+
:coupon_visibilities,
|
25
|
+
:distance_in_meters,
|
26
|
+
:latitude,
|
27
|
+
:longitude,
|
28
|
+
:merchant_devices,
|
29
|
+
:neighborhood_name,
|
30
|
+
:resolved_facebook_id,
|
31
|
+
:sms_id,
|
32
|
+
:street_address,
|
33
|
+
:geo_location
|
34
34
|
]
|
35
35
|
attr_accessor *PROPERTY_NAMES
|
36
36
|
|
37
|
+
EMBEDDED_PROPERTY_NAMES = [
|
38
|
+
:street_address
|
39
|
+
]
|
40
|
+
attr_accessor *EMBEDDED_PROPERTY_NAMES
|
41
|
+
|
37
42
|
require 'perka/model/street_address'
|
38
43
|
require 'perka/model/merchant'
|
39
44
|
TYPE_MAP = {
|
40
|
-
|
41
|
-
|
45
|
+
:street_address => Perka::Model::StreetAddress,
|
46
|
+
:merchant => Perka::Model::Merchant
|
42
47
|
}
|
43
48
|
|
44
49
|
end
|
data/lib/perka/version.rb
CHANGED
data/spec/api_integrator_spec.rb
CHANGED
@@ -10,145 +10,145 @@ API_BASE = 'https://sandbox.getperka.com'
|
|
10
10
|
|
11
11
|
describe Perka::PerkaApi do
|
12
12
|
context "as an integrator user" do
|
13
|
-
|
13
|
+
|
14
14
|
# sets up an api instance for all of our tests to use
|
15
15
|
before(:all) do
|
16
16
|
@api = Perka::PerkaApi.new({
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
:flatpack => Flatpack::Core::Flatpack.new({
|
18
|
+
:pretty => true,
|
19
|
+
:verbose => true,
|
20
|
+
:entity_module => Perka::Model
|
21
|
+
}),
|
22
|
+
:server_base => API_BASE,
|
23
|
+
:verbose => true
|
24
|
+
})
|
25
25
|
@api.oauth_integrator_login(INTEGRATOR_ID, INTEGRATOR_SECRET)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
# clear out all customer data before each test
|
29
29
|
before(:each) do
|
30
30
|
@api.integrator_destroy_delete.execute
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
it "creates a new managed customer" do
|
34
34
|
@api.oauth_integrator_login(INTEGRATOR_ID, INTEGRATOR_SECRET)
|
35
|
-
|
35
|
+
|
36
36
|
cred = Perka::Model::UserCredentials.new({
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
:email => 'joe@getperka.com',
|
38
|
+
:phone => '+15555555555'
|
39
|
+
})
|
40
40
|
customer = @api.integrator_customer_post(cred).execute
|
41
|
-
|
41
|
+
|
42
42
|
customer.unconfirmed_email.should eq('joe@getperka.com')
|
43
43
|
customer.unconfirmed_phone.should eq('+15555555555')
|
44
|
-
|
44
|
+
|
45
45
|
# another request with the same credentials should yield the same customer
|
46
46
|
new_customer = @api.integrator_customer_post(cred).execute
|
47
47
|
new_customer.uuid.should eq(customer.uuid)
|
48
|
-
|
49
|
-
# another request with the same email and different phone should
|
48
|
+
|
49
|
+
# another request with the same email and different phone should
|
50
50
|
# also yield the same customer
|
51
51
|
cred = Perka::Model::UserCredentials.new({
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
:email => 'joe@getperka.com',
|
53
|
+
:phone => '+17777777777'
|
54
|
+
})
|
55
55
|
new_customer = @api.integrator_customer_post(cred).execute
|
56
56
|
new_customer.uuid.should eq(customer.uuid)
|
57
|
-
|
57
|
+
|
58
58
|
# similarly, same phone and different email
|
59
59
|
cred = Perka::Model::UserCredentials.new({
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
:email => 'joe+another@getperka.com',
|
61
|
+
:phone => '+15555555555'
|
62
|
+
})
|
63
63
|
new_customer = @api.integrator_customer_post(cred).execute
|
64
64
|
new_customer.uuid.should eq(customer.uuid)
|
65
|
-
|
65
|
+
|
66
66
|
# another request with unique values should yield a new customer
|
67
67
|
cred = Perka::Model::UserCredentials.new({
|
68
|
-
|
69
|
-
|
68
|
+
:email => 'joe+yet_another@getperka.com'
|
69
|
+
})
|
70
70
|
new_customer = @api.integrator_customer_post(cred).execute
|
71
71
|
new_customer.uuid.should_not eq(customer.uuid)
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
it "rewards punches to a new customer" do
|
75
75
|
@api.oauth_integrator_login(INTEGRATOR_ID, INTEGRATOR_SECRET)
|
76
|
-
|
76
|
+
|
77
77
|
# we'll first create a new customer
|
78
78
|
cred = Perka::Model::UserCredentials.new(:email => 'joe+yet_another@getperka.com')
|
79
79
|
customer = @api.integrator_customer_post(cred).execute
|
80
|
-
|
80
|
+
|
81
81
|
# determine the merchants associated with this integrator account.
|
82
82
|
merchants = @api.integrator_managed_merchants_get.execute
|
83
|
-
|
83
|
+
|
84
84
|
# lets assume this integrator has only one managed merchant
|
85
85
|
merchant = merchants.first
|
86
|
-
|
87
|
-
# By default, API endpoints DO NOT return a full object graph of data.
|
86
|
+
|
87
|
+
# By default, API endpoints DO NOT return a full object graph of data.
|
88
88
|
# For example, the above integrator_managed_merchants_get endpoint returns
|
89
|
-
# only the merchant with no associated location or program data.
|
90
|
-
# describe_type_uuid_get endpoint is an exception to this rule, and will
|
91
|
-
# always peform a deep serialization of the entity being described.
|
89
|
+
# only the merchant with no associated location or program data. The
|
90
|
+
# describe_type_uuid_get endpoint is an exception to this rule, and will
|
91
|
+
# always peform a deep serialization of the entity being described. We'll
|
92
92
|
# now describe our merchant to gain access to our location and program data.
|
93
93
|
merchant = @api.describe_entity_get(merchant).execute
|
94
|
-
|
94
|
+
|
95
95
|
# The merchant's locations should now be populated
|
96
96
|
location = merchant.merchant_locations.first
|
97
|
-
|
97
|
+
|
98
98
|
# The program data should also be populated, so we can dig down and grab
|
99
99
|
# a program type that we'd like to award points for
|
100
100
|
program_type = merchant.program_tiers.first.programs.first.program_type
|
101
|
-
|
101
|
+
|
102
102
|
# now we'll switch our session over to a clerk at the merchant location.
|
103
103
|
# This will authorize our API to execute clerk enabled endpoints.
|
104
104
|
@api = @api.oauth_integrator_become("CLERK", location.uuid)
|
105
|
-
|
105
|
+
|
106
106
|
# we can now assign some loyalty punches to our new customer
|
107
107
|
visit = @api.customer_reward_put(Perka::Model::RewardGrant.new({
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
108
|
+
:customer => customer,
|
109
|
+
:reward_confirmations => [
|
110
|
+
Perka::Model::PunchRewardConfirmation.new({
|
111
|
+
:program_type => program_type,
|
112
|
+
:punches_earned => 2
|
113
|
+
})
|
114
|
+
]
|
115
|
+
})).execute
|
116
|
+
|
117
117
|
# A new visit should have been returned describing the transaction.
|
118
118
|
# The customer and merchant location should be what we specified
|
119
119
|
visit.customer.uuid.should eq(customer.uuid)
|
120
120
|
visit.merchant_location.uuid.should eq(location.uuid)
|
121
|
-
|
121
|
+
|
122
122
|
# A new reward should have been advanced by 2 punches
|
123
123
|
visit.reward_advancements.length.should eq(1)
|
124
124
|
advancement = visit.reward_advancements.first
|
125
125
|
advancement.punches_earned.should eq(2)
|
126
|
-
|
126
|
+
|
127
127
|
# The reward should show a sum of only 2 punches since this is a new customer
|
128
128
|
advancement.reward.punches_earned.should eq(2)
|
129
|
-
|
129
|
+
|
130
130
|
# We'll now pull down the customer's reward status
|
131
131
|
rewards = @api.customer_reward_get.with_customer_uuid(customer.uuid).execute
|
132
|
-
|
132
|
+
|
133
133
|
# We should have only one non-activated, non-redeemed reward with 2 punches
|
134
134
|
rewards.length.should eq(1)
|
135
135
|
rewards.first.activated_at.should be_nil
|
136
136
|
rewards.first.redeemed_at.should be_nil
|
137
137
|
rewards.first.punches_earned.should eq(2)
|
138
|
-
|
139
|
-
# Now we'll give the customer another 9 punches, which should activate the
|
140
|
-
# reward and make it available for redemption, and will create another
|
138
|
+
|
139
|
+
# Now we'll give the customer another 9 punches, which should activate the
|
140
|
+
# reward and make it available for redemption, and will create another
|
141
141
|
# reward with a single punch
|
142
142
|
@api.customer_reward_put(Perka::Model::RewardGrant.new({
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
143
|
+
:customer => customer,
|
144
|
+
:reward_confirmations => [
|
145
|
+
Perka::Model::PunchRewardConfirmation.new({
|
146
|
+
:program_type => program_type,
|
147
|
+
:punches_earned => 9
|
148
|
+
})
|
149
|
+
]
|
150
|
+
})).execute
|
151
|
+
|
152
152
|
# The customer should now one activated, and one non-activated reward
|
153
153
|
rewards = @api.customer_reward_get.with_customer_uuid(customer.uuid).execute
|
154
154
|
rewards.length.should eq(2)
|
@@ -156,28 +156,28 @@ describe Perka::PerkaApi do
|
|
156
156
|
active_reward.activated_at.should_not be_nil
|
157
157
|
active_reward.redeemed_at.should be_nil
|
158
158
|
active_reward.punches_earned.should eq(10)
|
159
|
-
|
159
|
+
|
160
160
|
inactive_reward = rewards.detect {|r| !r.activated_at }
|
161
161
|
inactive_reward.activated_at.should be_nil
|
162
162
|
inactive_reward.redeemed_at.should be_nil
|
163
163
|
inactive_reward.punches_earned.should eq(1)
|
164
|
-
|
165
|
-
# We'll now redeem the active reward.
|
164
|
+
|
165
|
+
# We'll now redeem the active reward. We can also award
|
166
166
|
# more punches in the same transaction
|
167
167
|
@api.customer_reward_put(Perka::Model::RewardGrant.new({
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
# The customer status should now show just one non-active
|
168
|
+
:customer => customer,
|
169
|
+
:reward_confirmations => [
|
170
|
+
Perka::Model::RedemptionRewardConfirmation.new({
|
171
|
+
:reward => active_reward
|
172
|
+
}),
|
173
|
+
Perka::Model::PunchRewardConfirmation.new({
|
174
|
+
:program_type => program_type,
|
175
|
+
:punches_earned => 1
|
176
|
+
})
|
177
|
+
]
|
178
|
+
})).execute
|
179
|
+
|
180
|
+
# The customer status should now show just one non-active
|
181
181
|
# reward with 2 punches
|
182
182
|
rewards = @api.customer_reward_get.with_customer_uuid(customer.uuid).execute
|
183
183
|
rewards.length.should eq(1)
|
@@ -185,26 +185,49 @@ describe Perka::PerkaApi do
|
|
185
185
|
rewards.first.redeemed_at.should be_nil
|
186
186
|
rewards.first.punches_earned.should eq(2)
|
187
187
|
end
|
188
|
-
|
188
|
+
|
189
189
|
it "annotate entities with arbitrary JSON data" do
|
190
190
|
@api.oauth_integrator_login(INTEGRATOR_ID, INTEGRATOR_SECRET)
|
191
|
-
|
191
|
+
|
192
192
|
# first we'll grab a reference to one of our managed merchants
|
193
193
|
merchants = @api.integrator_managed_merchants_get.execute
|
194
194
|
merchant = merchants.first
|
195
|
-
|
195
|
+
|
196
196
|
# then apply an arbitrary annotation to the merchant
|
197
197
|
json = "{'foo':'bar'}"
|
198
198
|
@api.annotation_put(Perka::Model::EntityAnnotation.new({
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
199
|
+
:annotation => json,
|
200
|
+
:entity => merchant
|
201
|
+
})).execute
|
202
|
+
|
203
203
|
# which can be retreived at any time
|
204
204
|
annotation = @api.annotation_entity_get(merchant).execute
|
205
205
|
annotation.annotation.should eq(json)
|
206
|
+
|
207
|
+
# now we'll update our annotation to a new value
|
208
|
+
json = "{'bar':'baz'}"
|
209
|
+
@api.annotation_put(Perka::Model::EntityAnnotation.new({
|
210
|
+
:annotation => json,
|
211
|
+
:entity => merchant
|
212
|
+
})).execute
|
213
|
+
|
214
|
+
# and verify the update
|
215
|
+
annotation = @api.annotation_entity_get(merchant).execute
|
216
|
+
annotation.annotation.should eq(json)
|
217
|
+
|
218
|
+
# let's also attempt to annotate an entity with at least one embedded property
|
219
|
+
merchant = @api.describe_entity_get(merchant).execute
|
220
|
+
location = merchant.merchant_locations.first
|
221
|
+
json = "{'foo':'bar'}"
|
222
|
+
@api.annotation_put(Perka::Model::EntityAnnotation.new({
|
223
|
+
:annotation => json,
|
224
|
+
:entity => location
|
225
|
+
})).execute
|
226
|
+
|
227
|
+
# which can be retreived at any time
|
228
|
+
annotation = @api.annotation_entity_get(location).execute
|
229
|
+
annotation.annotation.should eq(json)
|
230
|
+
|
206
231
|
end
|
207
|
-
|
208
232
|
end
|
209
|
-
|
210
|
-
end
|
233
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: "1.
|
8
|
+
- 2
|
9
|
+
version: "1.2"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Joe Stelmach
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-09
|
17
|
+
date: 2012-10-09 00:00:00 +05:30
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|