app_manager 1.7.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 939c279b78c14a7e781d74177e6df92a287a2e463d6c3af39346760e6891115b
4
- data.tar.gz: 9a3abefe3f42d4c40b34d597a0b850d128afbff33094cbe8ddf06b66dd473fb2
3
+ metadata.gz: 1093f4ae3ee06a00f81bf11ad98bb1669f6b9f931bed69a430525733058143a0
4
+ data.tar.gz: 9a3a425bdf82d12982f33ace1e86a1e5b47bbc7b3430ccd96b0469967cbf2f65
5
5
  SHA512:
6
- metadata.gz: 769614783e6d231a4b75303003b8da1143787d10cae09f093647bfeb6b246c28d4e604255a23530ad6332cad3d6796cec7fd99a80a3b5c46c8d74660f8dd17ee
7
- data.tar.gz: da7329819695c265587a36c8c34ef922176e5fd40a5109acd88849695bbbf1143eff43d2d699f08c044d90eaf58bb3f45ea5f5ec09fbbc9c5d34bcb2c980b6b9
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 (1.7.0)
4
+ app_manager (2.0.0)
5
5
  activerecord-import (~> 1.4)
6
6
  httparty
7
7
  kaminari (>= 0.16.3)
@@ -10,35 +10,35 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- actioncable (7.1.2)
14
- actionpack (= 7.1.2)
15
- activesupport (= 7.1.2)
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
18
  zeitwerk (~> 2.6)
19
- actionmailbox (7.1.2)
20
- actionpack (= 7.1.2)
21
- activejob (= 7.1.2)
22
- activerecord (= 7.1.2)
23
- activestorage (= 7.1.2)
24
- activesupport (= 7.1.2)
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)
25
25
  mail (>= 2.7.1)
26
26
  net-imap
27
27
  net-pop
28
28
  net-smtp
29
- actionmailer (7.1.2)
30
- actionpack (= 7.1.2)
31
- actionview (= 7.1.2)
32
- activejob (= 7.1.2)
33
- activesupport (= 7.1.2)
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)
34
34
  mail (~> 2.5, >= 2.5.4)
35
35
  net-imap
36
36
  net-pop
37
37
  net-smtp
38
38
  rails-dom-testing (~> 2.2)
39
- actionpack (7.1.2)
40
- actionview (= 7.1.2)
41
- activesupport (= 7.1.2)
39
+ actionpack (7.1.3.2)
40
+ actionview (= 7.1.3.2)
41
+ activesupport (= 7.1.3.2)
42
42
  nokogiri (>= 1.8.5)
43
43
  racc
44
44
  rack (>= 2.2.4)
@@ -46,37 +46,37 @@ GEM
46
46
  rack-test (>= 0.6.3)
47
47
  rails-dom-testing (~> 2.2)
48
48
  rails-html-sanitizer (~> 1.6)
49
- actiontext (7.1.2)
50
- actionpack (= 7.1.2)
51
- activerecord (= 7.1.2)
52
- activestorage (= 7.1.2)
53
- activesupport (= 7.1.2)
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)
54
54
  globalid (>= 0.6.0)
55
55
  nokogiri (>= 1.8.5)
56
- actionview (7.1.2)
57
- activesupport (= 7.1.2)
56
+ actionview (7.1.3.2)
57
+ activesupport (= 7.1.3.2)
58
58
  builder (~> 3.1)
59
59
  erubi (~> 1.11)
60
60
  rails-dom-testing (~> 2.2)
61
61
  rails-html-sanitizer (~> 1.6)
62
- activejob (7.1.2)
63
- activesupport (= 7.1.2)
62
+ activejob (7.1.3.2)
63
+ activesupport (= 7.1.3.2)
64
64
  globalid (>= 0.3.6)
65
- activemodel (7.1.2)
66
- activesupport (= 7.1.2)
67
- activerecord (7.1.2)
68
- activemodel (= 7.1.2)
69
- activesupport (= 7.1.2)
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
70
  timeout (>= 0.4.0)
71
71
  activerecord-import (1.5.1)
72
72
  activerecord (>= 4.2)
73
- activestorage (7.1.2)
74
- actionpack (= 7.1.2)
75
- activejob (= 7.1.2)
76
- activerecord (= 7.1.2)
77
- activesupport (= 7.1.2)
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)
78
78
  marcel (~> 1.0)
79
- activesupport (7.1.2)
79
+ activesupport (7.1.3.2)
80
80
  base64
81
81
  bigdecimal
82
82
  concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -89,10 +89,10 @@ GEM
89
89
  addressable (2.8.0)
90
90
  public_suffix (>= 2.0.2, < 5.0)
91
91
  base64 (0.2.0)
92
- bigdecimal (3.1.5)
92
+ bigdecimal (3.1.6)
93
93
  builder (3.2.4)
94
94
  coderay (1.1.3)
95
- concurrent-ruby (1.2.2)
95
+ concurrent-ruby (1.2.3)
96
96
  connection_pool (2.4.1)
97
97
  crack (0.4.5)
98
98
  rexml
@@ -100,8 +100,7 @@ GEM
100
100
  date (3.3.4)
101
101
  diff-lcs (1.5.0)
102
102
  dotenv (2.1.2)
103
- drb (2.2.0)
104
- ruby2_keywords
103
+ drb (2.2.1)
105
104
  erubi (1.12.0)
106
105
  globalid (1.2.1)
107
106
  activesupport (>= 6.1)
@@ -109,12 +108,12 @@ GEM
109
108
  httparty (0.21.0)
110
109
  mini_mime (>= 1.0.0)
111
110
  multi_xml (>= 0.5.2)
112
- i18n (1.14.1)
111
+ i18n (1.14.4)
113
112
  concurrent-ruby (~> 1.0)
114
- io-console (0.7.1)
115
- irb (1.11.0)
113
+ io-console (0.7.2)
114
+ irb (1.12.0)
116
115
  rdoc
117
- reline (>= 0.3.8)
116
+ reline (>= 0.4.2)
118
117
  kaminari (1.2.2)
119
118
  activesupport (>= 4.1.0)
120
119
  kaminari-actionview (= 1.2.2)
@@ -135,11 +134,11 @@ GEM
135
134
  net-imap
136
135
  net-pop
137
136
  net-smtp
138
- marcel (1.0.2)
137
+ marcel (1.0.4)
139
138
  method_source (1.0.0)
140
139
  mini_mime (1.1.5)
141
140
  mini_portile2 (2.8.5)
142
- minitest (5.20.0)
141
+ minitest (5.22.2)
143
142
  multi_xml (0.6.0)
144
143
  mutex_m (0.2.0)
145
144
  net-imap (0.3.7)
@@ -162,7 +161,7 @@ GEM
162
161
  stringio
163
162
  public_suffix (4.0.6)
164
163
  racc (1.7.3)
165
- rack (3.0.8)
164
+ rack (3.0.9.1)
166
165
  rack-session (2.0.0)
167
166
  rack (>= 3.0.0)
168
167
  rack-test (2.1.0)
@@ -170,20 +169,20 @@ GEM
170
169
  rackup (2.1.0)
171
170
  rack (>= 3)
172
171
  webrick (~> 1.8)
173
- rails (7.1.2)
174
- actioncable (= 7.1.2)
175
- actionmailbox (= 7.1.2)
176
- actionmailer (= 7.1.2)
177
- actionpack (= 7.1.2)
178
- actiontext (= 7.1.2)
179
- actionview (= 7.1.2)
180
- activejob (= 7.1.2)
181
- activemodel (= 7.1.2)
182
- activerecord (= 7.1.2)
183
- activestorage (= 7.1.2)
184
- activesupport (= 7.1.2)
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)
185
184
  bundler (>= 1.15.0)
186
- railties (= 7.1.2)
185
+ railties (= 7.1.3.2)
187
186
  rails-dom-testing (2.2.0)
188
187
  activesupport (>= 5.0.0)
189
188
  minitest
@@ -191,9 +190,9 @@ GEM
191
190
  rails-html-sanitizer (1.6.0)
192
191
  loofah (~> 2.21)
193
192
  nokogiri (~> 1.14)
194
- railties (7.1.2)
195
- actionpack (= 7.1.2)
196
- activesupport (= 7.1.2)
193
+ railties (7.1.3.2)
194
+ actionpack (= 7.1.3.2)
195
+ activesupport (= 7.1.3.2)
197
196
  irb
198
197
  rackup (>= 1.0.0)
199
198
  rake (>= 12.2)
@@ -202,7 +201,7 @@ GEM
202
201
  rake (13.0.6)
203
202
  rdoc (6.6.2)
204
203
  psych (>= 4.0.0)
205
- reline (0.4.2)
204
+ reline (0.4.3)
206
205
  io-console (~> 0.5)
207
206
  rexml (3.2.5)
208
207
  rspec (3.11.0)
@@ -220,9 +219,8 @@ GEM
220
219
  diff-lcs (>= 1.2.0, < 2.0)
221
220
  rspec-support (~> 3.11.0)
222
221
  rspec-support (3.11.0)
223
- ruby2_keywords (0.0.5)
224
222
  stringio (3.1.0)
225
- thor (1.3.0)
223
+ thor (1.3.1)
226
224
  timeout (0.4.1)
227
225
  tzinfo (2.0.6)
228
226
  concurrent-ruby (~> 1.0)
@@ -234,7 +232,7 @@ GEM
234
232
  websocket-driver (0.7.6)
235
233
  websocket-extensions (>= 0.1.0)
236
234
  websocket-extensions (0.1.5)
237
- zeitwerk (2.6.12)
235
+ zeitwerk (2.6.13)
238
236
 
239
237
  PLATFORMS
240
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,9 +58,12 @@ 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)
66
+ data = gq_obj.recurring_charge_api_call(plan_data, return_url, @shop,discount_cookie)
64
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}
@@ -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)
@@ -0,0 +1,5 @@
1
+ module AppManager
2
+ class Discount < AppManagerRecord
3
+ self.table_name = "discounts"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module AppManager
2
+ class DiscountLinkPlan < AppManagerRecord
3
+ self.table_name = "discount_link_plans"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module AppManager
2
+ class DiscountShop < AppManagerRecord
3
+ self.table_name = "discount_shops"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module AppManager
2
+ class DiscountUsageLog < AppManagerRecord
3
+ self.table_name = "discounts_usage_log"
4
+ end
5
+ end
@@ -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 : 30
32
- response = self.class.send(http_method, path, { body: options, timeout: time_out })
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
- else
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: 15 })
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("[Extens Trials] APP MANAGER >>>> #{e.inspect}")
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::ExtendTrial.bulk_import extend_plan_users
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
 
@@ -481,6 +612,68 @@ module AppManager
481
612
 
482
613
  end
483
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
+
484
677
  def store_local_charge(params, options)
485
678
  message = {"message" => 'fail'}
486
679
  if options
@@ -491,7 +684,7 @@ module AppManager
491
684
  test_value = charge["test"]
492
685
  plan_id = charge["plan_id"].to_i
493
686
  begin
494
- 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')
495
688
  message = {"message" => 'success'}
496
689
  rescue Exception => e
497
690
  Rollbar.error("Charge not saved on local DB due to #{e.inspect}")
@@ -511,12 +704,32 @@ module AppManager
511
704
  return message
512
705
  end
513
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
+
514
726
 
515
727
  def sync_app_manager
516
728
  plan_obj = AppManager::Client.new
517
729
  response = plan_obj.get_status
518
730
  if response && response.code == 200
519
731
  charges = AppManager::Charge.where(sync: false)
732
+ discounts_usage_logs = AppManager::DiscountUsageLog.where(sync: false, process_type: 'use-discount')
520
733
  charges.each do |charge|
521
734
  if charge
522
735
  if !charge["cancelled_on"].nil?
@@ -529,6 +742,17 @@ module AppManager
529
742
  end
530
743
  end
531
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
+
532
756
  end
533
757
  end
534
758
 
@@ -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,31 +83,73 @@ module AppManager
82
83
  end
83
84
  end
84
85
 
85
- discount_type = plan['discount_type'] || "percentage"
86
- discount_val = discount_type == "percentage" ? (plan['discount'].to_f/ 100) : "#{plan['discount']}"
87
- if !@api_version.nil? && @api_version.to_s.include?('2024')
88
- plan_discount = if plan['discount'] && plan['cycle_count']
89
- {
90
- "discount" => { "durationLimitInIntervals" => (plan['cycle_count'].to_i),
91
- "value" => {"#{discount_type}" => discount_val}
92
- }
93
- }
94
- elsif plan['discount']
95
- {
96
- "discount" => { "value" => {"#{discount_type}" => discount_val}
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
+ }
97
104
  }
98
- }
99
- else
100
- {}
101
- end
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
102
116
  else
103
- plan_discount = plan['discount'] ? { "discount" => { "durationLimitInIntervals" => (plan['cycle_count'].to_i), "value" => {"#{discount_type}" => discount_val} } } : {}
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
+
104
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)}"
147
+
105
148
  price_details = {
106
149
  "price": { "amount": plan['price'], "currencyCode": 'USD' },
107
150
  "interval": plan['interval']['value']
108
151
  }
109
- price_details.merge! plan_discount if plan_discount.any?
152
+ price_details.merge! plan_discount if plan_discount && plan_discount.any?
110
153
 
111
154
  plan_var = {
112
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppManager
4
- VERSION = "1.7.0"
4
+ VERSION = "2.0.0"
5
5
  end
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: 1.7.0
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: 2024-01-09 00:00:00.000000000 Z
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