app_manager 1.7.0 → 2.2.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: f97b31c44449e934975e233f07a745d883e58abd3a29ccd30537ec0e1ba6bca2
4
+ data.tar.gz: 863e6b243cd1c16839c4d5c9d7f3a3a0b1b47909ce613c9ff075e21d996ce314
5
5
  SHA512:
6
- metadata.gz: 769614783e6d231a4b75303003b8da1143787d10cae09f093647bfeb6b246c28d4e604255a23530ad6332cad3d6796cec7fd99a80a3b5c46c8d74660f8dd17ee
7
- data.tar.gz: da7329819695c265587a36c8c34ef922176e5fd40a5109acd88849695bbbf1143eff43d2d699f08c044d90eaf58bb3f45ea5f5ec09fbbc9c5d34bcb2c980b6b9
6
+ metadata.gz: 31f071cf42a3cfec28b0fae59cedfc72c2b24b80a85c237932acf0d118807977a961aa199ebd5435f5ddcb4f9310a27ac47589b35db953f39e61fbdd7e6d25d6
7
+ data.tar.gz: 67769978a3d30041d329e02a22432dad4d936a5254ac711e118a03be50101e11260aa22929a2c210ddbec027c44b60fa807f0c51dc494e6aac92a16033b8b83d
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.2.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
- activerecord-import (1.5.1)
71
+ activerecord-import (1.6.0)
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.7)
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
- mini_portile2 (2.8.5)
142
- minitest (5.20.0)
140
+ mini_portile2 (2.8.6)
141
+ minitest (5.22.3)
143
142
  multi_xml (0.6.0)
144
143
  mutex_m (0.2.0)
145
144
  net-imap (0.3.7)
@@ -149,10 +148,10 @@ GEM
149
148
  net-protocol
150
149
  net-protocol (0.2.2)
151
150
  timeout
152
- net-smtp (0.4.0.1)
151
+ net-smtp (0.5.0)
153
152
  net-protocol
154
- nio4r (2.7.0)
155
- nokogiri (1.15.5)
153
+ nio4r (2.7.1)
154
+ nokogiri (1.15.6)
156
155
  mini_portile2 (~> 2.8.2)
157
156
  racc (~> 1.4)
158
157
  pry (0.14.1)
@@ -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.10)
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,18 +190,18 @@ 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)
200
199
  thor (~> 1.0, >= 1.2.2)
201
200
  zeitwerk (~> 2.6)
202
201
  rake (13.0.6)
203
- rdoc (6.6.2)
202
+ rdoc (6.6.3.1)
204
203
  psych (>= 4.0.0)
205
- reline (0.4.2)
204
+ reline (0.5.1)
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:
@@ -41,6 +41,7 @@ module AppManager
41
41
  end
42
42
  if @shop.update(update_info)
43
43
  begin
44
+ plan_data['old_plan'] = params[:old_plan] || nil;
44
45
  AppManager::EventHandler.new('charge_created', {
45
46
  "plan" => plan_data,
46
47
  "charge" => nil,
@@ -58,9 +59,13 @@ module AppManager
58
59
  end
59
60
  end
60
61
  request_data = {'shop' => @shop.shopify_domain, 'timestamp' => Time.now.to_i, 'plan' => params[:plan_id]}
62
+ request_data.merge!('host' => params['host']) if params['host'].present?
63
+ request_data.merge!('old_plan' => params['old_plan']) if params['old_plan'].present?
64
+
61
65
  return_url = "#{app_url}#{plan_callback_path}?#{Rack::Utils.build_query(request_data)}"
62
66
  gq_obj = AppManager::GraphqlHelper.new(@shop.shopify_domain, @shop.shopify_token)
63
- data = gq_obj.recurring_charge_api_call(plan_data, return_url, @shop)
67
+ discount_local_storage = params[:discount_code].present? && !params[:discount_code].nil? ? params[:discount_code] : nil
68
+ data = gq_obj.recurring_charge_api_call(plan_data, return_url, @shop,discount_local_storage)
64
69
  if data.present? && !data["errors"].present? && (data["data"].present? && data["data"]["appSubscriptionCreate"].present? && (!data["data"]["appSubscriptionCreate"]["userErrors"].any? && data["data"]["appSubscriptionCreate"]["confirmationUrl"]))
65
70
  redirect_charge = data["data"]["appSubscriptionCreate"]["confirmationUrl"]
66
71
  render json: {'redirect_url' => redirect_charge}
@@ -85,6 +90,7 @@ module AppManager
85
90
  shopify_token = @field_names['shopify_token']
86
91
  shopify_domain = @field_names['name']
87
92
  grandfathered_field = @field_names['grandfathered']
93
+ discounted_plans = []
88
94
  if !@shop.nil?
89
95
  old_plan_id = @shop[@plan_field]
90
96
  old_plan_data = nil
@@ -131,8 +137,23 @@ module AppManager
131
137
  rescue Exception => e
132
138
  Rollbar.error("Error in APP MANAGER Charge Created Callback >>>> #{e.inspect}")
133
139
  end
140
+
141
+ begin
142
+ plan_obj = AppManager::Client.new
143
+ if params[:discount].present? && !params[:discount].nil?
144
+ discounted_plans = plan_obj.get_related_discounted_plans(params[:discount])
145
+ if discounted_plans.empty? || discounted_plans.include?(params[:plan].to_i)
146
+ plan_obj.discount_used(@shop[shopify_domain], params[:discount])
147
+ end
148
+ end
149
+ rescue
150
+ Rollbar.error("Error in APP MANAGER Discount used API call >>>> #{e.inspect}")
151
+ end
134
152
  end
135
153
  end
154
+
155
+
156
+
136
157
  embed_host = Base64.encode64(params[:shop] + "/admin")
137
158
 
138
159
  if !old_plan_id.nil?
@@ -65,8 +65,16 @@ module AppManager
65
65
  end
66
66
  end
67
67
 
68
+ promotional_discount = []
69
+ if params[:discount_code].present? && !params[:discount_code].nil? && @shop
70
+ discount_local_storage = params[:discount_code]
71
+ plan_obj = AppManager::Client.new
72
+ promotional_discount = plan_obj.get_promotional_discount(params[:shop_domain],discount_local_storage)
73
+ promotional_discount = [] if promotional_discount.class.to_s == "Hash" && promotional_discount.has_key?('status') && promotional_discount['status'] == 404
74
+ end
68
75
  response = {
69
76
  'plans' => plans,
77
+ 'promotional_discount' => promotional_discount,
70
78
  'shopify_plan' => shopify_plan,
71
79
  'plan' => plan,
72
80
  'default_plan_id' => default_plan_id,
@@ -90,12 +98,12 @@ module AppManager
90
98
  @shopify_email = AppManager.configuration.field_names['shopify_email']
91
99
  @shopify_plan_name_field = AppManager.configuration.field_names['shopify_plan']
92
100
  if params[:search]
93
- data = model.where("#{@shopify_domain} LIKE :search OR #{@shopify_email} LIKE :search", search: "%#{search}%")
101
+ data = model.where("#{@shopify_domain} LIKE :search OR #{@shopify_email} LIKE :search", search: "%#{search}%").order(sort + " " + order)
94
102
  data = data.where(@plan_field => plans) if !plans.nil?
95
103
  data = data.where(@shopify_plan_name_field => shopify_plans) if !shopify_plans.nil?
96
104
  data = data.page(params[:page]).per(items_per_page)
97
105
  else
98
- data = model
106
+ data = model.order(sort + " " + order)
99
107
  data = data.where(@plan_field => plans) if !plans.nil?
100
108
  data = data.where(@shopify_plan_name_field => shopify_plans) if !shopify_plans.nil?
101
109
  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: 120 })
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,12 @@ 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)
134
+ when 'get-related-discounted-plans'
135
+ return @fs.get_local_related_discounted_plans(params,options)
114
136
  else
115
137
  return nil
116
138
  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,21 @@ 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)
47
+ get("/discount?shop_domain=#{shop_domain}&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
57
+
58
+ def get_related_discounted_plans(discount_id)
59
+ get("/get-related-discounted-plans?discount_id=#{discount_id}")
60
+ end
45
61
 
46
62
  end
47
63
  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,106 @@ 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
+ promotional_discounts_data << AppManager::Discount.new(
228
+ discount_id: promotional_discount['id'],
229
+ name: promotional_discount['name'],
230
+ code: promotional_discount['code'],
231
+ discount_type: promotional_discount['type'] || 'amount',
232
+ value: promotional_discount['value'] || 0,
233
+ duration_intervals: promotional_discount['duration_intervals'],
234
+ max_usage: promotional_discount['max_usage'],
235
+ enabled: promotional_discount['enabled'],
236
+ valid_from: promotional_discount['valid_from'],
237
+ valid_to: promotional_discount['valid_to'],
238
+ priority: promotional_discount['priority'] || 0,
239
+ multiple_uses: promotional_discount['multiple_uses'],
240
+ multiple_apps: promotional_discount['multiple_apps'],
241
+ app_id: promotional_discount['app_id'] || 0,
242
+ created_at: promotional_discount['created_at'],
243
+ updated_at: promotional_discount['updated_at'],
244
+ deleted_at: promotional_discount['deleted_at']
245
+ )
246
+ end
247
+
248
+ AppManager::Discount.bulk_import promotional_discounts_data
249
+ end
250
+ end
251
+
252
+ def save_api_promotional_discounts_shops(promotional_discounts_shops)
253
+
254
+ begin
255
+ AppManager::DiscountShop.connection.truncate(AppManager::DiscountShop.table_name)
256
+ rescue
257
+ AppManager::DiscountShop.delete_all
258
+ end
259
+
260
+ if promotional_discounts_shops.any?
261
+ promotional_discounts_shop_data = []
262
+ promotional_discounts_shops.each do |promotional_discounts_shop|
263
+ promotional_discounts_shop_data << AppManager::DiscountShop.new(
264
+ discount_id: promotional_discounts_shop['discount_id'],
265
+ domain: promotional_discounts_shop['domain']
266
+ )
267
+ end
268
+ AppManager::DiscountShop.bulk_import promotional_discounts_shop_data
269
+ end
270
+ end
271
+
272
+ def save_api_promotional_discounts_link_plans(promotional_discounts_plans)
273
+
274
+ begin
275
+ AppManager::DiscountLinkPlan.connection.truncate(AppManager::DiscountLinkPlan.table_name)
276
+ rescue
277
+ AppManager::DiscountLinkPlan.delete_all
278
+ end
279
+
280
+ if promotional_discounts_plans.any?
281
+ discount_link_plans_data = []
282
+ promotional_discounts_plans.each do |link_plan|
283
+ discount_link_plans_data << AppManager::DiscountLinkPlan.new(
284
+ discount_id: link_plan['discount_id'],
285
+ plan_id: link_plan['plan_id']
286
+ )
287
+ end
288
+ AppManager::DiscountLinkPlan.bulk_import discount_link_plans_data
289
+ end
290
+ end
291
+
292
+ def save_api_promotional_discounts_usage_log(promotional_discounts_usage_log)
293
+ begin
294
+ AppManager::DiscountUsageLog.connection.truncate(AppManager::DiscountUsageLog.table_name)
295
+ rescue
296
+ AppManager::DiscountUsageLog.delete_all
297
+ end
298
+
299
+ if promotional_discounts_usage_log.any?
300
+ promotional_discounts_usage_log_data = []
301
+ promotional_discounts_usage_log.each do |log|
302
+ promotional_discounts_usage_log_data << AppManager::DiscountUsageLog.new(
303
+ discount_id: log['discount_id'],
304
+ app_id: log['app_id'],
305
+ domain: log['domain'],
306
+ sync: log['sync'],
307
+ process_type: log['process_type'],
308
+ created_at: log['created_at'],
309
+ updated_at: log['updated_at']
310
+ )
311
+ end
312
+ AppManager::DiscountUsageLog.bulk_import promotional_discounts_usage_log_data
189
313
  end
190
314
  end
191
315
 
@@ -481,6 +605,71 @@ module AppManager
481
605
 
482
606
  end
483
607
 
608
+ def get_local_discount(params, options)
609
+ code = [params['code']].pack('H*')
610
+ shop_domain = params['shop_domain']
611
+ now = Time.now
612
+
613
+ discount_data = AppManager::Discount.where(enabled: true)
614
+ .where('valid_from <= ?', now)
615
+ .where('valid_to IS NULL OR valid_to >= ?', now)
616
+ .where(code: code)
617
+ .first
618
+ return [] if discount_data.nil?
619
+
620
+ discount_shop = AppManager::DiscountShop.where(discount_id: discount_data.discount_id).count
621
+
622
+ discount_plan = AppManager::DiscountLinkPlan.where(discount_id: discount_data.discount_id).pluck('plan_id')
623
+
624
+ discount_usage = AppManager::DiscountUsageLog.where(discount_id: discount_data.discount_id).count
625
+
626
+ discount_usage_by_domain = AppManager::DiscountUsageLog.where(discount_id: discount_data.discount_id)
627
+ .where(domain: shop_domain)
628
+ .count
629
+ if discount_shop > 0
630
+ discount_shop_specific = AppManager::DiscountShop.where(discount_id: discount_data.discount_id)
631
+ .where(domain: shop_domain)
632
+ .first
633
+ return [] if discount_shop_specific.nil?
634
+ end
635
+
636
+ if discount_data.max_usage.present? && discount_data.max_usage != 0
637
+ return [] if discount_usage >= discount_data.max_usage
638
+ end
639
+
640
+ if discount_data.multiple_uses == false && discount_usage_by_domain >= 1
641
+ return []
642
+ end
643
+
644
+ if discount_data.multiple_apps == false
645
+ discount_usage_by_app = AppManager::DiscountUsageLog
646
+ .where(discount_id: discount_data.discount_id, domain: shop_domain)
647
+ .where.not(app_id: discount_data.app_id)
648
+ .first
649
+ return [] if discount_usage_by_app.present?
650
+ end
651
+
652
+
653
+ discount_data = discount_data.attributes.symbolize_keys
654
+ discount_data[:plan_relation] = discount_plan
655
+ final_mapped_data = {
656
+ "id" => discount_data[:discount_id],
657
+ "name" => discount_data[:name],
658
+ "type" => discount_data[:discount_type],
659
+ "value" => discount_data[:value].to_f,
660
+ "duration_intervals" => discount_data[:duration_intervals],
661
+ "plan_relation" => discount_data[:plan_relation]
662
+ } rescue {}
663
+
664
+ return JSON.parse(final_mapped_data.to_json)
665
+
666
+ end
667
+
668
+ def get_local_related_discounted_plans(params, options)
669
+ discounted_plans = DiscountLinkPlan.where(discount_id: params['discount_id']).pluck(:plan_id) rescue []
670
+ return discounted_plans
671
+ end
672
+
484
673
  def store_local_charge(params, options)
485
674
  message = {"message" => 'fail'}
486
675
  if options
@@ -491,7 +680,7 @@ module AppManager
491
680
  test_value = charge["test"]
492
681
  plan_id = charge["plan_id"].to_i
493
682
  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)
683
+ 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
684
  message = {"message" => 'success'}
496
685
  rescue Exception => e
497
686
  Rollbar.error("Charge not saved on local DB due to #{e.inspect}")
@@ -511,12 +700,32 @@ module AppManager
511
700
  return message
512
701
  end
513
702
 
703
+ def store_discount_used(params,options)
704
+ if options && options[:shop_domain].present? && options[:discount_id].present?
705
+ app_id = AppManager::Discount.where(discount_id: options[:discount_id])
706
+ .pluck(:app_id)
707
+ .first rescue nil
708
+ data = {
709
+ 'discount_id' => options[:discount_id],
710
+ 'domain' => options[:shop_domain],
711
+ 'sync' => false,
712
+ 'process_type' => 'use-discount',
713
+ 'app_id' => app_id
714
+ }
715
+ discount_usage_log = AppManager::DiscountUsageLog.create(data)
716
+ return { 'message' => discount_usage_log ? 'success' : 'fail' }
717
+ else
718
+ return {"message" => 'fail'}
719
+ end
720
+ end
721
+
514
722
 
515
723
  def sync_app_manager
516
724
  plan_obj = AppManager::Client.new
517
725
  response = plan_obj.get_status
518
726
  if response && response.code == 200
519
727
  charges = AppManager::Charge.where(sync: false)
728
+ discounts_usage_logs = AppManager::DiscountUsageLog.where(sync: false, process_type: 'use-discount')
520
729
  charges.each do |charge|
521
730
  if charge
522
731
  if !charge["cancelled_on"].nil?
@@ -529,6 +738,17 @@ module AppManager
529
738
  end
530
739
  end
531
740
  end
741
+
742
+ if discounts_usage_logs.any?
743
+ discounts_usage_logs.each do |discount_usage_log|
744
+ discount_obj = AppManager::Client.new
745
+ discount_response = discount_obj.sync_discount_usage_log(shop_domain: discount_usage_log['domain'], discount_id: discount_usage_log['discount_id'].to_i)
746
+ if discount_response && discount_response["data"] == "Saved"
747
+ AppManager::DiscountUsageLog.find_by(discount_id: discount_usage_log['discount_id'],sync: false).update(sync: true, process_type: nil)
748
+ end
749
+ end
750
+ end
751
+
532
752
  end
533
753
  end
534
754
 
@@ -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_local_storage)
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,70 @@ 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_local_storage.nil? && shop
88
+ plan_obj = AppManager::Client.new
89
+ promotional_discount = plan_obj.get_promotional_discount(shop.shopify_domain, discount_local_storage)
90
+ promotional_discount = [] if promotional_discount.class.to_s == "Hash" && promotional_discount.has_key?('status') && promotional_discount['status'] == 404
91
+ end
92
+
93
+ if !plan['discount'].nil? && plan['discount'] != 0
94
+ discount_type = plan['discount_type'] || "percentage"
95
+ discount_val = discount_type == "percentage" ? (plan['discount'].to_f/ 100) : "#{plan['discount']}"
96
+ if !@api_version.nil? && @api_version.to_s.include?('2024')
97
+ plan_discount = if plan['discount'] && plan['cycle_count']
98
+ {
99
+ "discount" => { "durationLimitInIntervals" => (plan['cycle_count'].to_i),
100
+ "value" => {"#{discount_type}" => discount_val}
101
+ }
97
102
  }
98
- }
99
- else
100
- {}
101
- end
103
+ elsif plan['discount']
104
+ {
105
+ "discount" => { "value" => {"#{discount_type}" => discount_val}
106
+ }
107
+ }
108
+ else
109
+ {}
110
+ end
111
+ else
112
+ plan_discount = plan['discount'] ? { "discount" => { "durationLimitInIntervals" => (plan['cycle_count'].to_i), "value" => {"#{discount_type}" => discount_val} } } : {}
113
+ end
102
114
  else
103
- plan_discount = plan['discount'] ? { "discount" => { "durationLimitInIntervals" => (plan['cycle_count'].to_i), "value" => {"#{discount_type}" => discount_val} } } : {}
115
+
116
+ if promotional_discount.any?
117
+
118
+ if promotional_discount['plan_relation'].any? && !promotional_discount['plan_relation'].include?(plan['id'])
119
+ plan_discount = {}
120
+ else
121
+
122
+ discount_type = promotional_discount['type'] || 'percentage'
123
+ discount_value = {
124
+ discount_type => discount_type == 'percentage' ? promotional_discount['value'].to_f / 100 : [promotional_discount['value'].to_f, plan['price']].min
125
+ }
126
+
127
+ discount = { 'value' => discount_value }
128
+
129
+ discount['durationLimitInIntervals'] = promotional_discount['duration_intervals'].to_i if promotional_discount['duration_intervals'].to_i.positive?
130
+ plan_discount = { "discount" => discount}
131
+
132
+ end
133
+
134
+ end
135
+
104
136
  end
137
+
138
+ discount_exists = !plan['discount'].nil? && plan['discount'] != 0
139
+ promotional_discount_applies = promotional_discount.present? && promotional_discount.any?
140
+ promotional_discount_id = discount_exists && promotional_discount_applies ? 0 : promotional_discount_applies ? promotional_discount['id'] : 0
141
+
142
+ return_url += "&discount=#{promotional_discount_id}"
143
+
144
+
105
145
  price_details = {
106
146
  "price": { "amount": plan['price'], "currencyCode": 'USD' },
107
147
  "interval": plan['interval']['value']
108
148
  }
109
- price_details.merge! plan_discount if plan_discount.any?
149
+ price_details.merge! plan_discount if plan_discount && plan_discount.any?
110
150
 
111
151
  plan_var = {
112
152
  "appRecurringPricingDetails": price_details,
@@ -0,0 +1,34 @@
1
+ require 'uri'
2
+
3
+ # app/middleware/set_cookie.rb
4
+ module AppManager
5
+ class SetLocalStorage
6
+ def initialize(app, condition,destination_url)
7
+ @app = app
8
+ @condition = condition
9
+ @destination_url = destination_url
10
+ end
11
+
12
+ def call(env)
13
+ request = Rack::Request.new(env)
14
+
15
+ if @condition.call(request)
16
+ url = URI.parse(request.url)
17
+ host = url.host
18
+ discount_code = request.path.split('/')[2] rescue ''
19
+ AppManager.clear_cache #clearing cache
20
+ # Set a 302 response with an external URL and a cookie
21
+ return [
22
+ 302,
23
+ {
24
+ 'Location' => "#{@destination_url}?discount_code=#{discount_code}" ,
25
+ 'Content-Type' => 'text/plain'
26
+ },
27
+ ['Redirecting to external URL with cookie']
28
+ ]
29
+ end
30
+
31
+ @app.call(env)
32
+ end
33
+ end
34
+ 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.2.0"
5
5
  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.2.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-04-19 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_local_storage.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