app_manager 1.6.3 → 2.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +122 -89
- data/README.md +36 -1
- data/app/controllers/app_manager/charges_controller.rb +23 -3
- data/app/controllers/app_manager/plans_controller.rb +13 -2
- data/app/model/app_manager/discount.rb +5 -0
- data/app/model/app_manager/discount_link_plan.rb +5 -0
- data/app/model/app_manager/discount_shop.rb +5 -0
- data/app/model/app_manager/discount_usage_log.rb +5 -0
- data/lib/app_manager/client/connection.rb +24 -4
- data/lib/app_manager/client/plans.rb +12 -0
- data/lib/app_manager/fail_safe.rb +232 -3
- data/lib/app_manager/graphql_helper.rb +65 -6
- data/lib/app_manager/set_cookie.rb +41 -0
- data/lib/app_manager/version.rb +1 -1
- data/lib/app_manager.rb +27 -0
- data/lib/generators/app_manager/install/install_generator.rb +8 -0
- data/lib/generators/app_manager/install/templates/add_discount_tables.erb +48 -0
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1093f4ae3ee06a00f81bf11ad98bb1669f6b9f931bed69a430525733058143a0
|
|
4
|
+
data.tar.gz: 9a3a425bdf82d12982f33ace1e86a1e5b47bbc7b3430ccd96b0469967cbf2f65
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9306209e778f2593afc88cdaf1f468f8c0ccefddd197e3ecfcb516301581577131975ed73dde14decae361454d32955f25c80220edab9cc755955f986d37a747
|
|
7
|
+
data.tar.gz: b0f6d9c366e807ebaa5d5fd5de056ecd3f7e93addfbdc944cda14ec915dc86a5e20d4b248426dfe04bc7c5962887d858fd01eed6de2bc4ae7c5976540e9c8c6a
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
app_manager (
|
|
4
|
+
app_manager (2.0.0)
|
|
5
5
|
activerecord-import (~> 1.4)
|
|
6
6
|
httparty
|
|
7
7
|
kaminari (>= 0.16.3)
|
|
@@ -10,93 +10,110 @@ PATH
|
|
|
10
10
|
GEM
|
|
11
11
|
remote: https://rubygems.org/
|
|
12
12
|
specs:
|
|
13
|
-
actioncable (7.
|
|
14
|
-
actionpack (= 7.
|
|
15
|
-
activesupport (= 7.
|
|
13
|
+
actioncable (7.1.3.2)
|
|
14
|
+
actionpack (= 7.1.3.2)
|
|
15
|
+
activesupport (= 7.1.3.2)
|
|
16
16
|
nio4r (~> 2.0)
|
|
17
17
|
websocket-driver (>= 0.6.1)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
zeitwerk (~> 2.6)
|
|
19
|
+
actionmailbox (7.1.3.2)
|
|
20
|
+
actionpack (= 7.1.3.2)
|
|
21
|
+
activejob (= 7.1.3.2)
|
|
22
|
+
activerecord (= 7.1.3.2)
|
|
23
|
+
activestorage (= 7.1.3.2)
|
|
24
|
+
activesupport (= 7.1.3.2)
|
|
24
25
|
mail (>= 2.7.1)
|
|
25
26
|
net-imap
|
|
26
27
|
net-pop
|
|
27
28
|
net-smtp
|
|
28
|
-
actionmailer (7.
|
|
29
|
-
actionpack (= 7.
|
|
30
|
-
actionview (= 7.
|
|
31
|
-
activejob (= 7.
|
|
32
|
-
activesupport (= 7.
|
|
29
|
+
actionmailer (7.1.3.2)
|
|
30
|
+
actionpack (= 7.1.3.2)
|
|
31
|
+
actionview (= 7.1.3.2)
|
|
32
|
+
activejob (= 7.1.3.2)
|
|
33
|
+
activesupport (= 7.1.3.2)
|
|
33
34
|
mail (~> 2.5, >= 2.5.4)
|
|
34
35
|
net-imap
|
|
35
36
|
net-pop
|
|
36
37
|
net-smtp
|
|
37
|
-
rails-dom-testing (~> 2.
|
|
38
|
-
actionpack (7.
|
|
39
|
-
actionview (= 7.
|
|
40
|
-
activesupport (= 7.
|
|
41
|
-
|
|
38
|
+
rails-dom-testing (~> 2.2)
|
|
39
|
+
actionpack (7.1.3.2)
|
|
40
|
+
actionview (= 7.1.3.2)
|
|
41
|
+
activesupport (= 7.1.3.2)
|
|
42
|
+
nokogiri (>= 1.8.5)
|
|
43
|
+
racc
|
|
44
|
+
rack (>= 2.2.4)
|
|
45
|
+
rack-session (>= 1.0.1)
|
|
42
46
|
rack-test (>= 0.6.3)
|
|
43
|
-
rails-dom-testing (~> 2.
|
|
44
|
-
rails-html-sanitizer (~> 1.
|
|
45
|
-
actiontext (7.
|
|
46
|
-
actionpack (= 7.
|
|
47
|
-
activerecord (= 7.
|
|
48
|
-
activestorage (= 7.
|
|
49
|
-
activesupport (= 7.
|
|
47
|
+
rails-dom-testing (~> 2.2)
|
|
48
|
+
rails-html-sanitizer (~> 1.6)
|
|
49
|
+
actiontext (7.1.3.2)
|
|
50
|
+
actionpack (= 7.1.3.2)
|
|
51
|
+
activerecord (= 7.1.3.2)
|
|
52
|
+
activestorage (= 7.1.3.2)
|
|
53
|
+
activesupport (= 7.1.3.2)
|
|
50
54
|
globalid (>= 0.6.0)
|
|
51
55
|
nokogiri (>= 1.8.5)
|
|
52
|
-
actionview (7.
|
|
53
|
-
activesupport (= 7.
|
|
56
|
+
actionview (7.1.3.2)
|
|
57
|
+
activesupport (= 7.1.3.2)
|
|
54
58
|
builder (~> 3.1)
|
|
55
|
-
erubi (~> 1.
|
|
56
|
-
rails-dom-testing (~> 2.
|
|
57
|
-
rails-html-sanitizer (~> 1.
|
|
58
|
-
activejob (7.
|
|
59
|
-
activesupport (= 7.
|
|
59
|
+
erubi (~> 1.11)
|
|
60
|
+
rails-dom-testing (~> 2.2)
|
|
61
|
+
rails-html-sanitizer (~> 1.6)
|
|
62
|
+
activejob (7.1.3.2)
|
|
63
|
+
activesupport (= 7.1.3.2)
|
|
60
64
|
globalid (>= 0.3.6)
|
|
61
|
-
activemodel (7.
|
|
62
|
-
activesupport (= 7.
|
|
63
|
-
activerecord (7.
|
|
64
|
-
activemodel (= 7.
|
|
65
|
-
activesupport (= 7.
|
|
66
|
-
|
|
65
|
+
activemodel (7.1.3.2)
|
|
66
|
+
activesupport (= 7.1.3.2)
|
|
67
|
+
activerecord (7.1.3.2)
|
|
68
|
+
activemodel (= 7.1.3.2)
|
|
69
|
+
activesupport (= 7.1.3.2)
|
|
70
|
+
timeout (>= 0.4.0)
|
|
71
|
+
activerecord-import (1.5.1)
|
|
67
72
|
activerecord (>= 4.2)
|
|
68
|
-
activestorage (7.
|
|
69
|
-
actionpack (= 7.
|
|
70
|
-
activejob (= 7.
|
|
71
|
-
activerecord (= 7.
|
|
72
|
-
activesupport (= 7.
|
|
73
|
+
activestorage (7.1.3.2)
|
|
74
|
+
actionpack (= 7.1.3.2)
|
|
75
|
+
activejob (= 7.1.3.2)
|
|
76
|
+
activerecord (= 7.1.3.2)
|
|
77
|
+
activesupport (= 7.1.3.2)
|
|
73
78
|
marcel (~> 1.0)
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
activesupport (7.1.3.2)
|
|
80
|
+
base64
|
|
81
|
+
bigdecimal
|
|
76
82
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
83
|
+
connection_pool (>= 2.2.5)
|
|
84
|
+
drb
|
|
77
85
|
i18n (>= 1.6, < 2)
|
|
78
86
|
minitest (>= 5.1)
|
|
87
|
+
mutex_m
|
|
79
88
|
tzinfo (~> 2.0)
|
|
80
89
|
addressable (2.8.0)
|
|
81
90
|
public_suffix (>= 2.0.2, < 5.0)
|
|
91
|
+
base64 (0.2.0)
|
|
92
|
+
bigdecimal (3.1.6)
|
|
82
93
|
builder (3.2.4)
|
|
83
94
|
coderay (1.1.3)
|
|
84
|
-
concurrent-ruby (1.2.
|
|
95
|
+
concurrent-ruby (1.2.3)
|
|
96
|
+
connection_pool (2.4.1)
|
|
85
97
|
crack (0.4.5)
|
|
86
98
|
rexml
|
|
87
99
|
crass (1.0.6)
|
|
88
|
-
date (3.3.
|
|
100
|
+
date (3.3.4)
|
|
89
101
|
diff-lcs (1.5.0)
|
|
90
102
|
dotenv (2.1.2)
|
|
103
|
+
drb (2.2.1)
|
|
91
104
|
erubi (1.12.0)
|
|
92
|
-
globalid (1.1
|
|
93
|
-
activesupport (>=
|
|
105
|
+
globalid (1.2.1)
|
|
106
|
+
activesupport (>= 6.1)
|
|
94
107
|
hashdiff (1.0.1)
|
|
95
108
|
httparty (0.21.0)
|
|
96
109
|
mini_mime (>= 1.0.0)
|
|
97
110
|
multi_xml (>= 0.5.2)
|
|
98
|
-
i18n (1.14.
|
|
111
|
+
i18n (1.14.4)
|
|
99
112
|
concurrent-ruby (~> 1.0)
|
|
113
|
+
io-console (0.7.2)
|
|
114
|
+
irb (1.12.0)
|
|
115
|
+
rdoc
|
|
116
|
+
reline (>= 0.4.2)
|
|
100
117
|
kaminari (1.2.2)
|
|
101
118
|
activesupport (>= 4.1.0)
|
|
102
119
|
kaminari-actionview (= 1.2.2)
|
|
@@ -109,7 +126,7 @@ GEM
|
|
|
109
126
|
activerecord
|
|
110
127
|
kaminari-core (= 1.2.2)
|
|
111
128
|
kaminari-core (1.2.2)
|
|
112
|
-
loofah (2.
|
|
129
|
+
loofah (2.22.0)
|
|
113
130
|
crass (~> 1.0.2)
|
|
114
131
|
nokogiri (>= 1.12.0)
|
|
115
132
|
mail (2.8.1)
|
|
@@ -117,61 +134,75 @@ GEM
|
|
|
117
134
|
net-imap
|
|
118
135
|
net-pop
|
|
119
136
|
net-smtp
|
|
120
|
-
marcel (1.0.
|
|
137
|
+
marcel (1.0.4)
|
|
121
138
|
method_source (1.0.0)
|
|
122
|
-
mini_mime (1.1.
|
|
123
|
-
mini_portile2 (2.8.
|
|
124
|
-
minitest (5.
|
|
139
|
+
mini_mime (1.1.5)
|
|
140
|
+
mini_portile2 (2.8.5)
|
|
141
|
+
minitest (5.22.2)
|
|
125
142
|
multi_xml (0.6.0)
|
|
126
|
-
|
|
143
|
+
mutex_m (0.2.0)
|
|
144
|
+
net-imap (0.3.7)
|
|
127
145
|
date
|
|
128
146
|
net-protocol
|
|
129
147
|
net-pop (0.1.2)
|
|
130
148
|
net-protocol
|
|
131
|
-
net-protocol (0.2.
|
|
149
|
+
net-protocol (0.2.2)
|
|
132
150
|
timeout
|
|
133
|
-
net-smtp (0.
|
|
151
|
+
net-smtp (0.4.0.1)
|
|
134
152
|
net-protocol
|
|
135
|
-
nio4r (2.
|
|
136
|
-
nokogiri (1.15.
|
|
153
|
+
nio4r (2.7.0)
|
|
154
|
+
nokogiri (1.15.5)
|
|
137
155
|
mini_portile2 (~> 2.8.2)
|
|
138
156
|
racc (~> 1.4)
|
|
139
157
|
pry (0.14.1)
|
|
140
158
|
coderay (~> 1.1)
|
|
141
159
|
method_source (~> 1.0)
|
|
160
|
+
psych (5.1.2)
|
|
161
|
+
stringio
|
|
142
162
|
public_suffix (4.0.6)
|
|
143
|
-
racc (1.7.
|
|
144
|
-
rack (
|
|
163
|
+
racc (1.7.3)
|
|
164
|
+
rack (3.0.9.1)
|
|
165
|
+
rack-session (2.0.0)
|
|
166
|
+
rack (>= 3.0.0)
|
|
145
167
|
rack-test (2.1.0)
|
|
146
168
|
rack (>= 1.3)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
169
|
+
rackup (2.1.0)
|
|
170
|
+
rack (>= 3)
|
|
171
|
+
webrick (~> 1.8)
|
|
172
|
+
rails (7.1.3.2)
|
|
173
|
+
actioncable (= 7.1.3.2)
|
|
174
|
+
actionmailbox (= 7.1.3.2)
|
|
175
|
+
actionmailer (= 7.1.3.2)
|
|
176
|
+
actionpack (= 7.1.3.2)
|
|
177
|
+
actiontext (= 7.1.3.2)
|
|
178
|
+
actionview (= 7.1.3.2)
|
|
179
|
+
activejob (= 7.1.3.2)
|
|
180
|
+
activemodel (= 7.1.3.2)
|
|
181
|
+
activerecord (= 7.1.3.2)
|
|
182
|
+
activestorage (= 7.1.3.2)
|
|
183
|
+
activesupport (= 7.1.3.2)
|
|
159
184
|
bundler (>= 1.15.0)
|
|
160
|
-
railties (= 7.
|
|
161
|
-
rails-dom-testing (2.0
|
|
162
|
-
activesupport (>=
|
|
185
|
+
railties (= 7.1.3.2)
|
|
186
|
+
rails-dom-testing (2.2.0)
|
|
187
|
+
activesupport (>= 5.0.0)
|
|
188
|
+
minitest
|
|
163
189
|
nokogiri (>= 1.6)
|
|
164
190
|
rails-html-sanitizer (1.6.0)
|
|
165
191
|
loofah (~> 2.21)
|
|
166
192
|
nokogiri (~> 1.14)
|
|
167
|
-
railties (7.
|
|
168
|
-
actionpack (= 7.
|
|
169
|
-
activesupport (= 7.
|
|
170
|
-
|
|
193
|
+
railties (7.1.3.2)
|
|
194
|
+
actionpack (= 7.1.3.2)
|
|
195
|
+
activesupport (= 7.1.3.2)
|
|
196
|
+
irb
|
|
197
|
+
rackup (>= 1.0.0)
|
|
171
198
|
rake (>= 12.2)
|
|
172
|
-
thor (~> 1.0)
|
|
173
|
-
zeitwerk (~> 2.
|
|
199
|
+
thor (~> 1.0, >= 1.2.2)
|
|
200
|
+
zeitwerk (~> 2.6)
|
|
174
201
|
rake (13.0.6)
|
|
202
|
+
rdoc (6.6.2)
|
|
203
|
+
psych (>= 4.0.0)
|
|
204
|
+
reline (0.4.3)
|
|
205
|
+
io-console (~> 0.5)
|
|
175
206
|
rexml (3.2.5)
|
|
176
207
|
rspec (3.11.0)
|
|
177
208
|
rspec-core (~> 3.11.0)
|
|
@@ -188,18 +219,20 @@ GEM
|
|
|
188
219
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
189
220
|
rspec-support (~> 3.11.0)
|
|
190
221
|
rspec-support (3.11.0)
|
|
191
|
-
|
|
192
|
-
|
|
222
|
+
stringio (3.1.0)
|
|
223
|
+
thor (1.3.1)
|
|
224
|
+
timeout (0.4.1)
|
|
193
225
|
tzinfo (2.0.6)
|
|
194
226
|
concurrent-ruby (~> 1.0)
|
|
195
227
|
webmock (3.14.0)
|
|
196
228
|
addressable (>= 2.8.0)
|
|
197
229
|
crack (>= 0.3.2)
|
|
198
230
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
199
|
-
|
|
231
|
+
webrick (1.8.1)
|
|
232
|
+
websocket-driver (0.7.6)
|
|
200
233
|
websocket-extensions (>= 0.1.0)
|
|
201
234
|
websocket-extensions (0.1.5)
|
|
202
|
-
zeitwerk (2.6.
|
|
235
|
+
zeitwerk (2.6.13)
|
|
203
236
|
|
|
204
237
|
PLATFORMS
|
|
205
238
|
ruby
|
data/README.md
CHANGED
|
@@ -209,8 +209,43 @@ and then you can use follwing methods with your shop objects.
|
|
|
209
209
|
@shop.active_shopfiy_charge_full #It will give shopify recurring charge graphql object with discounted price details
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
|
|
213
212
|
<a name="step4"></a>
|
|
213
|
+
### Discount Link Integration
|
|
214
|
+
|
|
215
|
+
* Update app manager vue package in Rails+Vue apps & for for non-vue apps, update css or js from npm package, minimum version should be 2.4.4
|
|
216
|
+
|
|
217
|
+
* Update app manager gem in your project's Gemfile
|
|
218
|
+
|
|
219
|
+
```ruby
|
|
220
|
+
gem 'app_manager', '2.0.0'
|
|
221
|
+
```
|
|
222
|
+
* In Rails project, in application.rb, add following line after require "rails/all" line
|
|
223
|
+
|
|
224
|
+
```ruby
|
|
225
|
+
require 'app_manager/set_cookie'
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
* In route.rb file, add following route with constraints
|
|
229
|
+
```ruby
|
|
230
|
+
condition = ->(request) { request.path_info.include?('/discount/') }
|
|
231
|
+
constraints(condition) do
|
|
232
|
+
get '/discount/*any', to: AppManager::SetCookie.new(Rails.application, condition)
|
|
233
|
+
end
|
|
234
|
+
```
|
|
235
|
+
* If updating gem from 1.6.1, then run these commands on rails root.
|
|
236
|
+
|
|
237
|
+
Note: In this command, Please do not overwrite app_manager.rb file so press n
|
|
238
|
+
```ruby
|
|
239
|
+
rails g app_manager:install
|
|
240
|
+
```
|
|
241
|
+
This will add a new migration file in your db/app_manager directory
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
rails db:migrate
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
<a name="step5"></a>
|
|
214
249
|
### Extras
|
|
215
250
|
|
|
216
251
|
* To view the app_manager ruby gem is working in your rails app you can use rails console and initialize app_manager instance like with App Manager Portal access:
|
|
@@ -58,17 +58,20 @@ module AppManager
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
request_data = {'shop' => @shop.shopify_domain, 'timestamp' => Time.now.to_i, 'plan' => params[:plan_id]}
|
|
61
|
+
request_data.merge!('host' => params['host']) if params['host'].present?
|
|
62
|
+
|
|
61
63
|
return_url = "#{app_url}#{plan_callback_path}?#{Rack::Utils.build_query(request_data)}"
|
|
64
|
+
discount_cookie = AppManager.resolve_from_cookies(self.request)
|
|
62
65
|
gq_obj = AppManager::GraphqlHelper.new(@shop.shopify_domain, @shop.shopify_token)
|
|
63
|
-
data = gq_obj.recurring_charge_api_call(plan_data, return_url, @shop)
|
|
64
|
-
if !data["errors"].present? && (data["data"].present? && data["data"]["appSubscriptionCreate"].present? && (!data["data"]["appSubscriptionCreate"]["userErrors"].any? && data["data"]["appSubscriptionCreate"]["confirmationUrl"]))
|
|
66
|
+
data = gq_obj.recurring_charge_api_call(plan_data, return_url, @shop,discount_cookie)
|
|
67
|
+
if data.present? && !data["errors"].present? && (data["data"].present? && data["data"]["appSubscriptionCreate"].present? && (!data["data"]["appSubscriptionCreate"]["userErrors"].any? && data["data"]["appSubscriptionCreate"]["confirmationUrl"]))
|
|
65
68
|
redirect_charge = data["data"]["appSubscriptionCreate"]["confirmationUrl"]
|
|
66
69
|
render json: {'redirect_url' => redirect_charge}
|
|
67
70
|
else
|
|
68
71
|
raise Error, "#{data.inspect}"
|
|
69
72
|
end
|
|
70
73
|
else
|
|
71
|
-
raise Error, "
|
|
74
|
+
raise Error, "Plan not found"
|
|
72
75
|
end
|
|
73
76
|
else
|
|
74
77
|
raise ModelNotFound, "Shop not found"
|
|
@@ -85,6 +88,8 @@ module AppManager
|
|
|
85
88
|
shopify_token = @field_names['shopify_token']
|
|
86
89
|
shopify_domain = @field_names['name']
|
|
87
90
|
grandfathered_field = @field_names['grandfathered']
|
|
91
|
+
discounted_plans = JSON.parse(params[:discounted_plans]) rescue []
|
|
92
|
+
discounted_plans = discounted_plans.map!(&:to_s) if discounted_plans.any?
|
|
88
93
|
if !@shop.nil?
|
|
89
94
|
old_plan_id = @shop[@plan_field]
|
|
90
95
|
old_plan_data = nil
|
|
@@ -131,8 +136,23 @@ module AppManager
|
|
|
131
136
|
rescue Exception => e
|
|
132
137
|
Rollbar.error("Error in APP MANAGER Charge Created Callback >>>> #{e.inspect}")
|
|
133
138
|
end
|
|
139
|
+
|
|
140
|
+
begin
|
|
141
|
+
plan_obj = AppManager::Client.new
|
|
142
|
+
discounted_plans_present = discounted_plans.present? && discounted_plans.any?
|
|
143
|
+
if params[:promo_discount].present? && discounted_plans_present && discounted_plans.include?(params[:plan])
|
|
144
|
+
plan_obj.discount_used(@shop[shopify_domain], params[:promo_discount])
|
|
145
|
+
elsif params[:promo_discount].present? && discounted_plans.blank?
|
|
146
|
+
plan_obj.discount_used(@shop[shopify_domain], params[:promo_discount])
|
|
147
|
+
end
|
|
148
|
+
rescue
|
|
149
|
+
Rollbar.error("Error in APP MANAGER Discount used API call >>>> #{e.inspect}")
|
|
150
|
+
end
|
|
134
151
|
end
|
|
135
152
|
end
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
136
156
|
embed_host = Base64.encode64(params[:shop] + "/admin")
|
|
137
157
|
|
|
138
158
|
if !old_plan_id.nil?
|
|
@@ -65,8 +65,19 @@ module AppManager
|
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
+
promotional_discount = []
|
|
69
|
+
discount_cookie = AppManager.resolve_from_cookies(self.request)
|
|
70
|
+
if discount_cookie && @shop
|
|
71
|
+
created_at = @shop[AppManager.configuration.field_names['created_at']]
|
|
72
|
+
reinstall = AppManager.check_if_reinstall(created_at)
|
|
73
|
+
plan_obj = AppManager::Client.new
|
|
74
|
+
promotional_discount = plan_obj.get_promotional_discount(params[:shop_domain], discount_cookie['codeType'], discount_cookie['code'], reinstall)
|
|
75
|
+
promotional_discount = [] if promotional_discount.class.to_s == "Hash" && promotional_discount.has_key?('status') && promotional_discount['status'] == 404
|
|
76
|
+
end
|
|
77
|
+
|
|
68
78
|
response = {
|
|
69
79
|
'plans' => plans,
|
|
80
|
+
'promotional_discount' => promotional_discount,
|
|
70
81
|
'shopify_plan' => shopify_plan,
|
|
71
82
|
'plan' => plan,
|
|
72
83
|
'default_plan_id' => default_plan_id,
|
|
@@ -90,12 +101,12 @@ module AppManager
|
|
|
90
101
|
@shopify_email = AppManager.configuration.field_names['shopify_email']
|
|
91
102
|
@shopify_plan_name_field = AppManager.configuration.field_names['shopify_plan']
|
|
92
103
|
if params[:search]
|
|
93
|
-
data = model.where("#{@shopify_domain} LIKE :search OR #{@shopify_email} LIKE :search", search: "%#{search}%")
|
|
104
|
+
data = model.where("#{@shopify_domain} LIKE :search OR #{@shopify_email} LIKE :search", search: "%#{search}%").order(sort + " " + order)
|
|
94
105
|
data = data.where(@plan_field => plans) if !plans.nil?
|
|
95
106
|
data = data.where(@shopify_plan_name_field => shopify_plans) if !shopify_plans.nil?
|
|
96
107
|
data = data.page(params[:page]).per(items_per_page)
|
|
97
108
|
else
|
|
98
|
-
data = model
|
|
109
|
+
data = model.order(sort + " " + order)
|
|
99
110
|
data = data.where(@plan_field => plans) if !plans.nil?
|
|
100
111
|
data = data.where(@shopify_plan_name_field => shopify_plans) if !shopify_plans.nil?
|
|
101
112
|
data = data.page(params[:page]).per(items_per_page)
|
|
@@ -28,8 +28,19 @@ module AppManager
|
|
|
28
28
|
response = response_from_cache_for_api(http_method, path, options)
|
|
29
29
|
failsafe_or_caching_done = true
|
|
30
30
|
else
|
|
31
|
-
time_out = Rails.env.development? ? 120 :
|
|
32
|
-
|
|
31
|
+
time_out = Rails.env.development? ? 120 : 120
|
|
32
|
+
begin
|
|
33
|
+
response = self.class.send(http_method, path, { body: options, timeout: time_out })
|
|
34
|
+
rescue Net::ReadTimeout => error
|
|
35
|
+
# Handle timeout error here
|
|
36
|
+
Rails.logger.info "Net::ReadTimeout: Request timed out. Please try again."
|
|
37
|
+
response = response_from_failsafe(path, options)
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
# Handle other errors
|
|
40
|
+
Rails.logger.info "Error: #{e.message}"
|
|
41
|
+
response = response_from_failsafe(path, options)
|
|
42
|
+
end
|
|
43
|
+
|
|
33
44
|
end
|
|
34
45
|
if path.include? "/get-status"
|
|
35
46
|
data = response
|
|
@@ -42,7 +53,10 @@ module AppManager
|
|
|
42
53
|
data = parse_data(response.parsed_response)
|
|
43
54
|
# data = response_from_failsafe(path,options) #uncomment to test failsafe
|
|
44
55
|
return data
|
|
45
|
-
|
|
56
|
+
elsif ((response.class == Hash) && response.has_key?("message"))
|
|
57
|
+
data = parse_data(response)
|
|
58
|
+
return data
|
|
59
|
+
else
|
|
46
60
|
if failsafe_or_caching_done == true
|
|
47
61
|
data = response
|
|
48
62
|
return data
|
|
@@ -60,7 +74,7 @@ module AppManager
|
|
|
60
74
|
return fetch_static_cached_response(cache_key)
|
|
61
75
|
end
|
|
62
76
|
begin
|
|
63
|
-
response = self.class.send(http_method, path, { body: options, timeout:
|
|
77
|
+
response = self.class.send(http_method, path, { body: options, timeout: 1 })
|
|
64
78
|
if response.class.to_s == "HTTParty::Response" && (response.code.to_s.start_with?('2') or response.code.to_s.start_with?('4')) && (response.code.to_s != '429')
|
|
65
79
|
Rails.cache.write(cache_key, response, expires_in: AppManager.configuration.expires_in)
|
|
66
80
|
else
|
|
@@ -68,6 +82,8 @@ module AppManager
|
|
|
68
82
|
end
|
|
69
83
|
rescue Net::ReadTimeout => error
|
|
70
84
|
response = response_from_failsafe(path,options)
|
|
85
|
+
rescue StandardError => error
|
|
86
|
+
response = response_from_failsafe(path, options)
|
|
71
87
|
rescue Exception => e
|
|
72
88
|
response = response_from_failsafe(path,options)
|
|
73
89
|
end
|
|
@@ -111,6 +127,10 @@ module AppManager
|
|
|
111
127
|
return @fs.get_local_charge(params,options)
|
|
112
128
|
when 'has-plan'
|
|
113
129
|
return @fs.get_local_has_plan(params, options)
|
|
130
|
+
when 'discount'
|
|
131
|
+
return @fs.get_local_discount(params, options)
|
|
132
|
+
when 'use-discount'
|
|
133
|
+
return @fs.store_discount_used(params,options)
|
|
114
134
|
else
|
|
115
135
|
return nil
|
|
116
136
|
end
|
|
@@ -26,6 +26,7 @@ module AppManager
|
|
|
26
26
|
post("/sync-charge", options)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
|
|
29
30
|
def get_remaining_days(shop_domain, trial_activated_at = nil, plan_id = nil)
|
|
30
31
|
get("/get-remaining-days?shop_domain=#{shop_domain}&trial_activated_at=#{trial_activated_at}&plan_id=#{plan_id}")
|
|
31
32
|
end
|
|
@@ -42,6 +43,17 @@ module AppManager
|
|
|
42
43
|
get("/has-plan?shop_domain=#{shop_domain}&plan_id=#{plan_id}&trial_activated_at=#{trial_activated_at}&grandfathered=#{grandfathered}")
|
|
43
44
|
end
|
|
44
45
|
|
|
46
|
+
def get_promotional_discount(shop_domain = nil, code_type, code, reinstall)
|
|
47
|
+
get("/discount?shop_domain=#{shop_domain}&reinstall=#{reinstall}&code_type=#{code_type}&code=#{code}")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def discount_used(shop_domain, discount_id)
|
|
51
|
+
post('/use-discount', {shop_domain: shop_domain, discount_id: discount_id.to_i})
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def sync_discount_usage_log(options = {})
|
|
55
|
+
post("/use-discount-sync", options)
|
|
56
|
+
end
|
|
45
57
|
|
|
46
58
|
end
|
|
47
59
|
end
|
|
@@ -52,7 +52,7 @@ module AppManager
|
|
|
52
52
|
begin
|
|
53
53
|
save_api_extend_trials(params["extend_trials"])
|
|
54
54
|
rescue Exception => e
|
|
55
|
-
Rollbar.error("[
|
|
55
|
+
Rollbar.error("[Extend Trials] APP MANAGER >>>> #{e.inspect}")
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
begin
|
|
@@ -60,6 +60,31 @@ module AppManager
|
|
|
60
60
|
rescue Exception => e
|
|
61
61
|
Rollbar.error("[Plan User] APP MANAGER >>>> #{e.inspect}")
|
|
62
62
|
end
|
|
63
|
+
|
|
64
|
+
begin
|
|
65
|
+
save_api_promotional_discounts(params["promotional_discounts"])
|
|
66
|
+
rescue Exception => e
|
|
67
|
+
Rollbar.error("[Promotional discounts] APP MANAGER >>>> #{e.inspect}")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
begin
|
|
71
|
+
save_api_promotional_discounts_shops(params["promotional_discounts_shops"])
|
|
72
|
+
rescue Exception => e
|
|
73
|
+
Rollbar.error("[Promotional discounts shops] APP MANAGER >>>> #{e.inspect}")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
begin
|
|
77
|
+
save_api_promotional_discounts_link_plans(params["promotional_discounts_plans"])
|
|
78
|
+
rescue Exception => e
|
|
79
|
+
Rollbar.error("[Promotional discounts plans] APP MANAGER >>>> #{e.inspect}")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
begin
|
|
83
|
+
save_api_promotional_discounts_usage_log(params["promotional_discounts_usage_log"])
|
|
84
|
+
rescue Exception => e
|
|
85
|
+
Rollbar.error("[Promotional discounts usage log] APP MANAGER >>>> #{e.inspect}")
|
|
86
|
+
end
|
|
87
|
+
|
|
63
88
|
end
|
|
64
89
|
|
|
65
90
|
def save_api_plans(plans)
|
|
@@ -185,7 +210,113 @@ module AppManager
|
|
|
185
210
|
extend_plan_users << AppManager::PlanUser.new(plan_user_id: plan_user['id'],shop_domain: plan_user['shop_domain'], plan_id: plan_user['plan_id'], created_by: plan_user['created_by'], created_at: plan_user['created_at'], updated_at: plan_user['updated_at'])
|
|
186
211
|
# extend_plan_users << AppManager::PlanUser.new(id: plan_user['id'], shop_domain: plan_user['shop_domain'], plan_id: plan_user['plan_id'], created_by: plan_user['created_by'], created_at: plan_user['created_at'], updated_at: plan_user['updated_at'])
|
|
187
212
|
end
|
|
188
|
-
AppManager::
|
|
213
|
+
AppManager::PlanUser.bulk_import extend_plan_users
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def save_api_promotional_discounts(promotional_discounts)
|
|
218
|
+
begin
|
|
219
|
+
AppManager::Discount.connection.truncate(AppManager::Discount.table_name)
|
|
220
|
+
rescue
|
|
221
|
+
AppManager::Discount.delete_all
|
|
222
|
+
end
|
|
223
|
+
if promotional_discounts.any?
|
|
224
|
+
promotional_discounts_data = []
|
|
225
|
+
promotional_discounts.each do |promotional_discount|
|
|
226
|
+
|
|
227
|
+
Rails.logger.info " "
|
|
228
|
+
Rails.logger.info "=== promotional_discount===========#{promotional_discount.inspect}"
|
|
229
|
+
Rails.logger.info " "
|
|
230
|
+
|
|
231
|
+
promotional_discounts_data << AppManager::Discount.new(
|
|
232
|
+
discount_id: promotional_discount['id'],
|
|
233
|
+
name: promotional_discount['name'],
|
|
234
|
+
code: promotional_discount['code'],
|
|
235
|
+
discount_type: promotional_discount['type'] || 'amount',
|
|
236
|
+
value: promotional_discount['value'] || 0,
|
|
237
|
+
duration_intervals: promotional_discount['duration_intervals'],
|
|
238
|
+
max_usage: promotional_discount['max_usage'],
|
|
239
|
+
enabled: promotional_discount['enabled'],
|
|
240
|
+
valid_from: promotional_discount['valid_from'],
|
|
241
|
+
valid_to: promotional_discount['valid_to'],
|
|
242
|
+
priority: promotional_discount['priority'] || 0,
|
|
243
|
+
multiple_uses: promotional_discount['multiple_uses'],
|
|
244
|
+
multiple_apps: promotional_discount['multiple_apps'],
|
|
245
|
+
app_id: promotional_discount['app_id'] || 0,
|
|
246
|
+
created_at: promotional_discount['created_at'],
|
|
247
|
+
updated_at: promotional_discount['updated_at'],
|
|
248
|
+
deleted_at: promotional_discount['deleted_at']
|
|
249
|
+
)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
Rails.logger.info " "
|
|
253
|
+
Rails.logger.info "=== promotional_discounts_data===========#{promotional_discounts_data.inspect}"
|
|
254
|
+
Rails.logger.info " "
|
|
255
|
+
AppManager::Discount.bulk_import promotional_discounts_data
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def save_api_promotional_discounts_shops(promotional_discounts_shops)
|
|
260
|
+
|
|
261
|
+
begin
|
|
262
|
+
AppManager::DiscountShop.connection.truncate(AppManager::DiscountShop.table_name)
|
|
263
|
+
rescue
|
|
264
|
+
AppManager::DiscountShop.delete_all
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
if promotional_discounts_shops.any?
|
|
268
|
+
promotional_discounts_shop_data = []
|
|
269
|
+
promotional_discounts_shops.each do |promotional_discounts_shop|
|
|
270
|
+
promotional_discounts_shop_data << AppManager::DiscountShop.new(
|
|
271
|
+
discount_id: promotional_discounts_shop['discount_id'],
|
|
272
|
+
domain: promotional_discounts_shop['domain']
|
|
273
|
+
)
|
|
274
|
+
end
|
|
275
|
+
AppManager::DiscountShop.bulk_import promotional_discounts_shop_data
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def save_api_promotional_discounts_link_plans(promotional_discounts_plans)
|
|
280
|
+
|
|
281
|
+
begin
|
|
282
|
+
AppManager::DiscountLinkPlan.connection.truncate(AppManager::DiscountLinkPlan.table_name)
|
|
283
|
+
rescue
|
|
284
|
+
AppManager::DiscountLinkPlan.delete_all
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
if promotional_discounts_plans.any?
|
|
288
|
+
discount_link_plans_data = []
|
|
289
|
+
promotional_discounts_plans.each do |link_plan|
|
|
290
|
+
discount_link_plans_data << AppManager::DiscountLinkPlan.new(
|
|
291
|
+
discount_id: link_plan['discount_id'],
|
|
292
|
+
plan_id: link_plan['plan_id']
|
|
293
|
+
)
|
|
294
|
+
end
|
|
295
|
+
AppManager::DiscountLinkPlan.bulk_import discount_link_plans_data
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def save_api_promotional_discounts_usage_log(promotional_discounts_usage_log)
|
|
300
|
+
begin
|
|
301
|
+
AppManager::DiscountUsageLog.connection.truncate(AppManager::DiscountUsageLog.table_name)
|
|
302
|
+
rescue
|
|
303
|
+
AppManager::DiscountUsageLog.delete_all
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
if promotional_discounts_usage_log.any?
|
|
307
|
+
promotional_discounts_usage_log_data = []
|
|
308
|
+
promotional_discounts_usage_log.each do |log|
|
|
309
|
+
promotional_discounts_usage_log_data << AppManager::DiscountUsageLog.new(
|
|
310
|
+
discount_id: log['discount_id'],
|
|
311
|
+
app_id: log['app_id'],
|
|
312
|
+
domain: log['domain'],
|
|
313
|
+
sync: log['sync'],
|
|
314
|
+
process_type: log['process_type'],
|
|
315
|
+
created_at: log['created_at'],
|
|
316
|
+
updated_at: log['updated_at']
|
|
317
|
+
)
|
|
318
|
+
end
|
|
319
|
+
AppManager::DiscountUsageLog.bulk_import promotional_discounts_usage_log_data
|
|
189
320
|
end
|
|
190
321
|
end
|
|
191
322
|
|
|
@@ -262,6 +393,9 @@ module AppManager
|
|
|
262
393
|
value = eval(value)
|
|
263
394
|
value = value.each { |e| e.delete("id") }.each { |e| e.delete("created_at") }.each { |e| e.delete("updated_at") }
|
|
264
395
|
new_plan[key] = value
|
|
396
|
+
elsif ['plan_id'].include?(key)
|
|
397
|
+
# puts value.inspect
|
|
398
|
+
new_plan["id"] = value if value rescue {}
|
|
265
399
|
else
|
|
266
400
|
new_plan[key] = value unless key.class == Integer
|
|
267
401
|
end
|
|
@@ -350,6 +484,8 @@ module AppManager
|
|
|
350
484
|
new_plan[key] = (value == 0 || value == false ? false : true)
|
|
351
485
|
elsif ['test'].include?(key)
|
|
352
486
|
new_plan[key] = (value == 0 || value == false ? nil : true)
|
|
487
|
+
elsif ['plan_id'].include?(key)
|
|
488
|
+
new_plan["id"] = value if value rescue nil
|
|
353
489
|
else
|
|
354
490
|
new_plan[key] = value unless key.class == Integer
|
|
355
491
|
end
|
|
@@ -476,6 +612,68 @@ module AppManager
|
|
|
476
612
|
|
|
477
613
|
end
|
|
478
614
|
|
|
615
|
+
def get_local_discount(params, options)
|
|
616
|
+
code = [params['code']].pack('H*')
|
|
617
|
+
code_type = params['code_type']
|
|
618
|
+
reinstall = params['reinstall']
|
|
619
|
+
shop_domain = params['shop_domain']
|
|
620
|
+
now = Time.now
|
|
621
|
+
|
|
622
|
+
discount_data = AppManager::Discount.where(enabled: true)
|
|
623
|
+
.where('valid_from <= ?', now)
|
|
624
|
+
.where('valid_to >= ?', now)
|
|
625
|
+
.where(code: code)
|
|
626
|
+
.first
|
|
627
|
+
return [] if discount_data.nil?
|
|
628
|
+
|
|
629
|
+
discount_shop = AppManager::DiscountShop.where(discount_id: discount_data.discount_id).count
|
|
630
|
+
|
|
631
|
+
discount_plan = AppManager::DiscountLinkPlan.where(discount_id: discount_data.discount_id).pluck('plan_id')
|
|
632
|
+
|
|
633
|
+
discount_usage = AppManager::DiscountUsageLog.where(discount_id: discount_data.discount_id).count
|
|
634
|
+
|
|
635
|
+
discount_usage_by_domain = AppManager::DiscountUsageLog.where(discount_id: discount_data.discount_id)
|
|
636
|
+
.where(domain: shop_domain)
|
|
637
|
+
.count
|
|
638
|
+
if discount_shop > 0
|
|
639
|
+
discount_shop_specific = AppManager::DiscountShop.where(discount_id: discount_data.discount_id)
|
|
640
|
+
.where(domain: shop_domain)
|
|
641
|
+
.first
|
|
642
|
+
return [] if discount_shop_specific.nil?
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
if discount_data.max_usage.present? && discount_data.max_usage != 0
|
|
646
|
+
return [] if discount_usage >= discount_data.max_usage
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
if discount_data.multiple_uses == false && discount_usage_by_domain >= 1
|
|
650
|
+
return []
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
if discount_data.multiple_apps == false
|
|
654
|
+
discount_usage_by_app = AppManager::DiscountUsageLog
|
|
655
|
+
.where(discount_id: discount_data.discount_id, domain: shop_domain)
|
|
656
|
+
.where.not(app_id: discount_data.app_id)
|
|
657
|
+
.first
|
|
658
|
+
return [] if discount_usage_by_app.present?
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
discount_data = discount_data.attributes.symbolize_keys
|
|
663
|
+
discount_data[:plan_relation] = discount_plan
|
|
664
|
+
final_mapped_data = {
|
|
665
|
+
"id" => discount_data[:discount_id],
|
|
666
|
+
"name" => discount_data[:name],
|
|
667
|
+
"type" => discount_data[:discount_type],
|
|
668
|
+
"value" => discount_data[:value].to_f,
|
|
669
|
+
"duration_intervals" => discount_data[:duration_intervals],
|
|
670
|
+
"plan_relation" => discount_data[:plan_relation]
|
|
671
|
+
} rescue {}
|
|
672
|
+
|
|
673
|
+
return JSON.parse(final_mapped_data.to_json)
|
|
674
|
+
|
|
675
|
+
end
|
|
676
|
+
|
|
479
677
|
def store_local_charge(params, options)
|
|
480
678
|
message = {"message" => 'fail'}
|
|
481
679
|
if options
|
|
@@ -486,7 +684,7 @@ module AppManager
|
|
|
486
684
|
test_value = charge["test"]
|
|
487
685
|
plan_id = charge["plan_id"].to_i
|
|
488
686
|
begin
|
|
489
|
-
AppManager::Charge.create(charge_id: charge["charge_id"], test: test_value, status: charge["status"], name: charge["name"], type: charge["type"], price: charge["price"], interval: charge["interval"], trial_days: charge["trial_days"], billing_on: charge["billing_on"], activated_on: charge["activated_on"], trial_ends_on: charge["trial_ends_on"], cancelled_on: charge["cancelled_on"], expires_on: charge["expires_on"], plan_id: plan_id, description: charge["description"], shop_domain: charge["shop_domain"], created_at: charge["created_at"], updated_at: charge["updated_at"], sync: 0)
|
|
687
|
+
AppManager::Charge.create(charge_id: charge["charge_id"], test: test_value, status: charge["status"], name: charge["name"], type: charge["type"], price: charge["price"], interval: charge["interval"], trial_days: charge["trial_days"], billing_on: charge["billing_on"], activated_on: charge["activated_on"], trial_ends_on: charge["trial_ends_on"], cancelled_on: charge["cancelled_on"], expires_on: charge["expires_on"], plan_id: plan_id, description: charge["description"], shop_domain: charge["shop_domain"], created_at: charge["created_at"], updated_at: charge["updated_at"], sync: 0, process_type: 'store-charge')
|
|
490
688
|
message = {"message" => 'success'}
|
|
491
689
|
rescue Exception => e
|
|
492
690
|
Rollbar.error("Charge not saved on local DB due to #{e.inspect}")
|
|
@@ -506,12 +704,32 @@ module AppManager
|
|
|
506
704
|
return message
|
|
507
705
|
end
|
|
508
706
|
|
|
707
|
+
def store_discount_used(params,options)
|
|
708
|
+
if options && options[:shop_domain].present? && options[:discount_id].present?
|
|
709
|
+
app_id = AppManager::Discount.where(discount_id: options[:discount_id])
|
|
710
|
+
.pluck(:app_id)
|
|
711
|
+
.first rescue nil
|
|
712
|
+
data = {
|
|
713
|
+
'discount_id' => options[:discount_id],
|
|
714
|
+
'domain' => options[:shop_domain],
|
|
715
|
+
'sync' => false,
|
|
716
|
+
'process_type' => 'use-discount',
|
|
717
|
+
'app_id' => app_id
|
|
718
|
+
}
|
|
719
|
+
discount_usage_log = AppManager::DiscountUsageLog.create(data)
|
|
720
|
+
return { 'message' => discount_usage_log ? 'success' : 'fail' }
|
|
721
|
+
else
|
|
722
|
+
return {"message" => 'fail'}
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
|
|
509
726
|
|
|
510
727
|
def sync_app_manager
|
|
511
728
|
plan_obj = AppManager::Client.new
|
|
512
729
|
response = plan_obj.get_status
|
|
513
730
|
if response && response.code == 200
|
|
514
731
|
charges = AppManager::Charge.where(sync: false)
|
|
732
|
+
discounts_usage_logs = AppManager::DiscountUsageLog.where(sync: false, process_type: 'use-discount')
|
|
515
733
|
charges.each do |charge|
|
|
516
734
|
if charge
|
|
517
735
|
if !charge["cancelled_on"].nil?
|
|
@@ -524,6 +742,17 @@ module AppManager
|
|
|
524
742
|
end
|
|
525
743
|
end
|
|
526
744
|
end
|
|
745
|
+
|
|
746
|
+
if discounts_usage_logs.any?
|
|
747
|
+
discounts_usage_logs.each do |discount_usage_log|
|
|
748
|
+
discount_obj = AppManager::Client.new
|
|
749
|
+
discount_response = discount_obj.sync_discount_usage_log(shop_domain: discount_usage_log['domain'], discount_id: discount_usage_log['discount_id'].to_i)
|
|
750
|
+
if discount_response && discount_response["data"] == "Saved"
|
|
751
|
+
AppManager::DiscountUsageLog.find_by(discount_id: discount_usage_log['discount_id'],sync: false).update(sync: true, process_type: nil)
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
end
|
|
755
|
+
|
|
527
756
|
end
|
|
528
757
|
end
|
|
529
758
|
|
|
@@ -33,7 +33,7 @@ module AppManager
|
|
|
33
33
|
response = ActiveSupport::JSON.decode(response.read_body) rescue nil
|
|
34
34
|
return response
|
|
35
35
|
else
|
|
36
|
-
Rollbar.error("=== params missing from any of these api_key, api_version, shopify_domain, shopify_token
|
|
36
|
+
Rollbar.error("=== params missing from any of these api_key=#{@api_key}, api_version=#{@api_version}, shopify_domain=#{@shopify_domain}, shopify_token ===#{@shopify_token}")
|
|
37
37
|
return []
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -54,7 +54,7 @@ module AppManager
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def recurring_charge_api_call(plan,return_url,shop)
|
|
57
|
+
def recurring_charge_api_call(plan,return_url,shop,discount_cookie)
|
|
58
58
|
plan_test = nil
|
|
59
59
|
shop_plan_field = AppManager.configuration.field_names['shopify_plan'] rescue nil
|
|
60
60
|
if !plan['affiliate'].nil? && plan['affiliate'].any? && !shop_plan_field.nil? && plan['affiliate'].map{|e| e['value']}.include?(shop[shop_plan_field])
|
|
@@ -67,6 +67,7 @@ module AppManager
|
|
|
67
67
|
remaining_obj = AppManager::Client.new
|
|
68
68
|
remaining = remaining_obj.get_remaining_days(shop.shopify_domain,trial_activated_at,plan_id_field)
|
|
69
69
|
# trial_days = !remaining.nil? ? remaining : trial_days
|
|
70
|
+
|
|
70
71
|
if !remaining.nil?
|
|
71
72
|
if !plan_id_field.nil?
|
|
72
73
|
plan_obj = AppManager::Client.new
|
|
@@ -82,15 +83,73 @@ module AppManager
|
|
|
82
83
|
end
|
|
83
84
|
end
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
promotional_discount = []
|
|
87
|
+
if discount_cookie && shop
|
|
88
|
+
created_at = shop[AppManager.configuration.field_names['created_at']]
|
|
89
|
+
reinstall = AppManager.check_if_reinstall(created_at)
|
|
90
|
+
plan_obj = AppManager::Client.new
|
|
91
|
+
promotional_discount = plan_obj.get_promotional_discount(shop.shopify_domain, discount_cookie['codeType'], discount_cookie['code'], reinstall)
|
|
92
|
+
promotional_discount = [] if promotional_discount.class.to_s == "Hash" && promotional_discount.has_key?('status') && promotional_discount['status'] == 404
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if !plan['discount'].nil? && plan['discount'] != 0
|
|
96
|
+
discount_type = plan['discount_type'] || "percentage"
|
|
97
|
+
discount_val = discount_type == "percentage" ? (plan['discount'].to_f/ 100) : "#{plan['discount']}"
|
|
98
|
+
if !@api_version.nil? && @api_version.to_s.include?('2024')
|
|
99
|
+
plan_discount = if plan['discount'] && plan['cycle_count']
|
|
100
|
+
{
|
|
101
|
+
"discount" => { "durationLimitInIntervals" => (plan['cycle_count'].to_i),
|
|
102
|
+
"value" => {"#{discount_type}" => discount_val}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
elsif plan['discount']
|
|
106
|
+
{
|
|
107
|
+
"discount" => { "value" => {"#{discount_type}" => discount_val}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else
|
|
111
|
+
{}
|
|
112
|
+
end
|
|
113
|
+
else
|
|
114
|
+
plan_discount = plan['discount'] ? { "discount" => { "durationLimitInIntervals" => (plan['cycle_count'].to_i), "value" => {"#{discount_type}" => discount_val} } } : {}
|
|
115
|
+
end
|
|
116
|
+
else
|
|
117
|
+
|
|
118
|
+
if promotional_discount.any?
|
|
119
|
+
|
|
120
|
+
if promotional_discount['plan_relation'].any? && !promotional_discount['plan_relation'].include?(plan['id'])
|
|
121
|
+
plan_discount = {}
|
|
122
|
+
else
|
|
123
|
+
|
|
124
|
+
discount_type = promotional_discount['type'] || 'percentage'
|
|
125
|
+
discount_value = {
|
|
126
|
+
discount_type => discount_type == 'percentage' ? promotional_discount['value'].to_f / 100 : [promotional_discount['value'].to_f, plan['price']].min
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
discount = { 'value' => discount_value }
|
|
130
|
+
|
|
131
|
+
discount['durationLimitInIntervals'] = promotional_discount['duration_intervals'].to_i if promotional_discount['duration_intervals'].to_i.positive?
|
|
132
|
+
plan_discount = { "discount" => discount}
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
discount_exists = !plan['discount'].nil? && plan['discount'] != 0
|
|
141
|
+
promotional_discount_applies = promotional_discount.present? && promotional_discount.any?
|
|
142
|
+
promotional_discount_id = discount_exists && promotional_discount_applies ? 0 : promotional_discount_applies ? promotional_discount['id'] : 0
|
|
143
|
+
|
|
144
|
+
plans_relation = promotional_discount.present? && promotional_discount['plan_relation'].any? ? promotional_discount['plan_relation'] : []
|
|
145
|
+
# Append additional data to the existing return_url
|
|
146
|
+
return_url += "&promo_discount=#{promotional_discount_id}&discounted_plans=#{Rack::Utils.escape(plans_relation.to_json)}"
|
|
88
147
|
|
|
89
148
|
price_details = {
|
|
90
149
|
"price": { "amount": plan['price'], "currencyCode": 'USD' },
|
|
91
150
|
"interval": plan['interval']['value']
|
|
92
151
|
}
|
|
93
|
-
price_details.merge! plan_discount if plan_discount.any?
|
|
152
|
+
price_details.merge! plan_discount if plan_discount && plan_discount.any?
|
|
94
153
|
|
|
95
154
|
plan_var = {
|
|
96
155
|
"appRecurringPricingDetails": price_details,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# app/middleware/set_cookie_middleware.rb
|
|
2
|
+
require 'action_dispatch/middleware/cookies'
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
# app/middleware/set_cookie.rb
|
|
6
|
+
module AppManager
|
|
7
|
+
class SetCookie
|
|
8
|
+
def initialize(app, condition)
|
|
9
|
+
@app = app
|
|
10
|
+
@condition = condition
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(env)
|
|
14
|
+
request = Rack::Request.new(env)
|
|
15
|
+
|
|
16
|
+
if @condition.call(request)
|
|
17
|
+
url = URI.parse(request.url)
|
|
18
|
+
host = url.host
|
|
19
|
+
discount_code = request.path.split('/')[2]
|
|
20
|
+
|
|
21
|
+
# Set a cookie named 'ShopCircleDiscount' with the extracted values
|
|
22
|
+
lifetime = Time.now + 60 * 60 * 24 * 365
|
|
23
|
+
cookie_value = discount_code
|
|
24
|
+
|
|
25
|
+
AppManager.clear_cache #clearing cache
|
|
26
|
+
# Set a 302 response with an external URL and a cookie
|
|
27
|
+
return [
|
|
28
|
+
302,
|
|
29
|
+
{
|
|
30
|
+
'Location' => 'https://admin.shopify.com/admin/apps/'+ENV['SHOPIFY_APP_SLUG']+'/home/plan' ,
|
|
31
|
+
'Set-Cookie' => "ShopCircleDiscount=#{cookie_value}; expires=#{lifetime.utc.strftime('%a, %d %b %Y %H:%M:%S GMT')}; path=/; domain=#{host}; secure; HttpOnly; SameSite=None",
|
|
32
|
+
'Content-Type' => 'text/plain'
|
|
33
|
+
},
|
|
34
|
+
['Redirecting to external URL with cookie']
|
|
35
|
+
]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
@app.call(env)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/app_manager/version.rb
CHANGED
data/lib/app_manager.rb
CHANGED
|
@@ -16,8 +16,25 @@ require "app_manager/model"
|
|
|
16
16
|
require "app_manager/fail_safe"
|
|
17
17
|
require 'app_manager/railtie' if defined?(Rails)
|
|
18
18
|
require 'app_manager/exceptions'
|
|
19
|
+
require 'action_dispatch/middleware/cookies' if defined?(Rails)
|
|
20
|
+
require "action_controller"
|
|
19
21
|
|
|
20
22
|
module AppManager
|
|
23
|
+
module CookiesHandler
|
|
24
|
+
include ActionController::Cookies
|
|
25
|
+
|
|
26
|
+
def self.resolve_from_cookies(request)
|
|
27
|
+
if request.cookies['ShopCircleDiscount'].present?
|
|
28
|
+
{
|
|
29
|
+
'codeType' => 'normal',
|
|
30
|
+
'code' => request.cookies['ShopCircleDiscount']
|
|
31
|
+
}
|
|
32
|
+
else
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
21
38
|
def self.configure
|
|
22
39
|
yield configuration
|
|
23
40
|
end
|
|
@@ -34,4 +51,14 @@ module AppManager
|
|
|
34
51
|
end
|
|
35
52
|
end
|
|
36
53
|
|
|
54
|
+
def self.resolve_from_cookies(request)
|
|
55
|
+
CookiesHandler.resolve_from_cookies(request)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.check_if_reinstall(created_at)
|
|
59
|
+
created_at < (Time.now - 5.minutes) ? 1 : 0
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
37
64
|
end
|
|
@@ -39,6 +39,14 @@ module AppManager
|
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
def create_discount_table_migration
|
|
43
|
+
if self.class.migration_exists?("db/app_manager", "add_discount_tables")
|
|
44
|
+
say_status("skipped", "Migration add_discount_tables.rb already exists")
|
|
45
|
+
else
|
|
46
|
+
migration_template("add_discount_tables.erb", "db/app_manager/add_discount_tables.rb")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
42
50
|
|
|
43
51
|
private
|
|
44
52
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class AddDiscountTables < ActiveRecord::Migration[<%= rails_migration_version %>]
|
|
2
|
+
def change
|
|
3
|
+
create_table :discounts do |t|
|
|
4
|
+
t.bigint :discount_id
|
|
5
|
+
t.string :name
|
|
6
|
+
t.string :code
|
|
7
|
+
t.string :discount_type, default: 'amount'
|
|
8
|
+
t.decimal :value, default: 0
|
|
9
|
+
t.integer :duration_intervals
|
|
10
|
+
t.integer :max_usage
|
|
11
|
+
t.boolean :enabled, default: true
|
|
12
|
+
t.datetime :valid_from
|
|
13
|
+
t.datetime :valid_to
|
|
14
|
+
t.integer :priority, default: 0
|
|
15
|
+
t.boolean :multiple_uses, default: true
|
|
16
|
+
t.boolean :multiple_apps, default: true
|
|
17
|
+
t.integer :app_id, default: 0
|
|
18
|
+
t.timestamps
|
|
19
|
+
t.datetime :deleted_at
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
create_table :discount_shops do |t|
|
|
23
|
+
t.bigint :discount_id, index: true, foreign_key: true
|
|
24
|
+
t.string :domain
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
create_table :discounts_usage_log do |t|
|
|
28
|
+
t.bigint :discount_id, index: true, foreign_key: true
|
|
29
|
+
t.bigint :app_id, index: true, foreign_key: true
|
|
30
|
+
t.string :domain
|
|
31
|
+
t.boolean :sync, default: true
|
|
32
|
+
t.string :process_type
|
|
33
|
+
t.timestamps
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
create_table :discount_link_plans do |t|
|
|
37
|
+
t.bigint :discount_id, index: true, foreign_key: true
|
|
38
|
+
t.bigint :plan_id, index: true, foreign_key: true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def down
|
|
43
|
+
drop_table :discounts
|
|
44
|
+
drop_table :discount_shops
|
|
45
|
+
drop_table :discounts_usage_log
|
|
46
|
+
drop_table :discount_link_plans
|
|
47
|
+
end
|
|
48
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: app_manager
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rahul Tiwari @ Hulkapps
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-03-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: httparty
|
|
@@ -89,7 +89,11 @@ files:
|
|
|
89
89
|
- app/model/app_manager/app_manager_record.rb
|
|
90
90
|
- app/model/app_manager/app_structure.rb
|
|
91
91
|
- app/model/app_manager/charge.rb
|
|
92
|
+
- app/model/app_manager/discount.rb
|
|
93
|
+
- app/model/app_manager/discount_link_plan.rb
|
|
92
94
|
- app/model/app_manager/discount_plan.rb
|
|
95
|
+
- app/model/app_manager/discount_shop.rb
|
|
96
|
+
- app/model/app_manager/discount_usage_log.rb
|
|
93
97
|
- app/model/app_manager/extend_trial.rb
|
|
94
98
|
- app/model/app_manager/plan.rb
|
|
95
99
|
- app/model/app_manager/plan_user.rb
|
|
@@ -115,9 +119,11 @@ files:
|
|
|
115
119
|
- lib/app_manager/protection.rb
|
|
116
120
|
- lib/app_manager/railtie.rb
|
|
117
121
|
- lib/app_manager/response_cache.rb
|
|
122
|
+
- lib/app_manager/set_cookie.rb
|
|
118
123
|
- lib/app_manager/tasks/sync/local_app_manager.rake
|
|
119
124
|
- lib/app_manager/version.rb
|
|
120
125
|
- lib/generators/app_manager/install/install_generator.rb
|
|
126
|
+
- lib/generators/app_manager/install/templates/add_discount_tables.erb
|
|
121
127
|
- lib/generators/app_manager/install/templates/add_external_charge_field.erb
|
|
122
128
|
- lib/generators/app_manager/install/templates/add_plan_trial_grandfathered_to_shops.erb
|
|
123
129
|
- lib/generators/app_manager/install/templates/app_manager.rb.tt
|