kapso-client-ruby 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +81 -81
  3. data/CHANGELOG.md +262 -91
  4. data/Gemfile +20 -20
  5. data/RAILS_INTEGRATION.md +477 -477
  6. data/README.md +1053 -752
  7. data/Rakefile +40 -40
  8. data/TEMPLATE_TOOLS_GUIDE.md +120 -120
  9. data/WHATSAPP_24_HOUR_GUIDE.md +133 -133
  10. data/examples/advanced_features.rb +352 -349
  11. data/examples/advanced_messaging.rb +241 -0
  12. data/examples/basic_messaging.rb +139 -136
  13. data/examples/enhanced_interactive.rb +400 -0
  14. data/examples/flows_usage.rb +307 -0
  15. data/examples/interactive_messages.rb +343 -0
  16. data/examples/media_management.rb +256 -253
  17. data/examples/rails/jobs.rb +387 -387
  18. data/examples/rails/models.rb +239 -239
  19. data/examples/rails/notifications_controller.rb +226 -226
  20. data/examples/template_management.rb +393 -390
  21. data/kapso-ruby-logo.jpg +0 -0
  22. data/lib/kapso_client_ruby/client.rb +321 -316
  23. data/lib/kapso_client_ruby/errors.rb +348 -329
  24. data/lib/kapso_client_ruby/rails/generators/install_generator.rb +75 -75
  25. data/lib/kapso_client_ruby/rails/generators/templates/env.erb +20 -20
  26. data/lib/kapso_client_ruby/rails/generators/templates/initializer.rb.erb +32 -32
  27. data/lib/kapso_client_ruby/rails/generators/templates/message_service.rb.erb +137 -137
  28. data/lib/kapso_client_ruby/rails/generators/templates/webhook_controller.rb.erb +61 -61
  29. data/lib/kapso_client_ruby/rails/railtie.rb +54 -54
  30. data/lib/kapso_client_ruby/rails/service.rb +188 -188
  31. data/lib/kapso_client_ruby/rails/tasks.rake +166 -166
  32. data/lib/kapso_client_ruby/resources/calls.rb +172 -172
  33. data/lib/kapso_client_ruby/resources/contacts.rb +190 -190
  34. data/lib/kapso_client_ruby/resources/conversations.rb +103 -103
  35. data/lib/kapso_client_ruby/resources/flows.rb +382 -0
  36. data/lib/kapso_client_ruby/resources/media.rb +205 -205
  37. data/lib/kapso_client_ruby/resources/messages.rb +760 -380
  38. data/lib/kapso_client_ruby/resources/phone_numbers.rb +85 -85
  39. data/lib/kapso_client_ruby/resources/templates.rb +283 -283
  40. data/lib/kapso_client_ruby/types.rb +348 -262
  41. data/lib/kapso_client_ruby/version.rb +5 -5
  42. data/lib/kapso_client_ruby.rb +75 -74
  43. data/scripts/.env.example +17 -17
  44. data/scripts/kapso_template_finder.rb +91 -91
  45. data/scripts/sdk_setup.rb +404 -404
  46. data/scripts/test.rb +60 -60
  47. metadata +12 -3
@@ -1,388 +1,388 @@
1
- # frozen_string_literal: true
2
-
3
- # Background jobs for WhatsApp message sending
4
- # These jobs handle asynchronous message sending to improve performance
5
-
6
- class SendWelcomeMessageJob < ApplicationJob
7
- queue_as :whatsapp_messages
8
-
9
- retry_on KapsoClientRuby::RateLimitError, wait: :exponentially_longer, attempts: 5
10
- retry_on KapsoClientRuby::TemporaryError, wait: 30.seconds, attempts: 3
11
-
12
- discard_on KapsoClientRuby::AuthenticationError
13
- discard_on KapsoClientRuby::ValidationError
14
-
15
- def perform(user)
16
- return unless user.phone_number.present?
17
-
18
- service = KapsoMessageService.new
19
-
20
- begin
21
- result = service.send_welcome_message(user)
22
-
23
- if result && result.dig('messages', 0, 'id')
24
- # Track the message
25
- WhatsappMessage.track_message(
26
- user: user,
27
- message_id: result.dig('messages', 0, 'id'),
28
- message_type: 'welcome',
29
- phone_number: user.phone_number,
30
- messageable: user
31
- )
32
-
33
- Rails.logger.info "Welcome message sent to user #{user.id}: #{result.dig('messages', 0, 'id')}"
34
- end
35
-
36
- rescue KapsoClientRuby::Error => e
37
- Rails.logger.error "Failed to send welcome message to user #{user.id}: #{e.message}"
38
-
39
- # Track failed message
40
- WhatsappMessage.create!(
41
- user: user,
42
- message_id: "failed_#{SecureRandom.hex(8)}",
43
- message_type: 'welcome',
44
- phone_number: user.phone_number,
45
- messageable: user,
46
- status: 'failed',
47
- error_message: e.message,
48
- sent_at: Time.current
49
- )
50
-
51
- raise # Re-raise to trigger retry logic
52
- end
53
- end
54
- end
55
-
56
- class SendOrderConfirmationJob < ApplicationJob
57
- queue_as :whatsapp_messages
58
-
59
- retry_on KapsoClientRuby::RateLimitError, wait: :exponentially_longer, attempts: 5
60
- retry_on KapsoClientRuby::TemporaryError, wait: 30.seconds, attempts: 3
61
-
62
- def perform(user, order)
63
- return unless user.phone_number.present?
64
-
65
- service = KapsoMessageService.new
66
-
67
- begin
68
- result = service.send_order_confirmation(order)
69
-
70
- if result && result.dig('messages', 0, 'id')
71
- WhatsappMessage.track_message(
72
- user: user,
73
- message_id: result.dig('messages', 0, 'id'),
74
- message_type: 'order_confirmation',
75
- phone_number: user.phone_number,
76
- messageable: order
77
- )
78
-
79
- Rails.logger.info "Order confirmation sent for order #{order.id}: #{result.dig('messages', 0, 'id')}"
80
- end
81
-
82
- rescue KapsoClientRuby::Error => e
83
- Rails.logger.error "Failed to send order confirmation for order #{order.id}: #{e.message}"
84
- raise
85
- end
86
- end
87
- end
88
-
89
- class SendOrderStatusUpdateJob < ApplicationJob
90
- queue_as :whatsapp_messages
91
-
92
- retry_on KapsoClientRuby::RateLimitError, wait: :exponentially_longer, attempts: 5
93
-
94
- def perform(user, order)
95
- return unless user.phone_number.present?
96
-
97
- # Don't spam users with too many updates
98
- return if user.received_message_type_recently?('order_status_update', within: 1.hour)
99
-
100
- service = KapsoClientRuby::Rails::Service.new
101
-
102
- begin
103
- # Use different templates based on order status
104
- template_name = case order.status
105
- when 'confirmed' then 'order_confirmed'
106
- when 'processing' then 'order_processing'
107
- when 'shipped' then 'order_shipped'
108
- when 'delivered' then 'order_delivered'
109
- when 'cancelled' then 'order_cancelled'
110
- else 'order_status_update'
111
- end
112
-
113
- components = build_order_status_components(order, user)
114
-
115
- result = service.send_template_message(
116
- to: user.phone_number,
117
- template_name: template_name,
118
- language: user.preferred_language || 'en',
119
- components: components
120
- )
121
-
122
- if result && result.dig('messages', 0, 'id')
123
- WhatsappMessage.track_message(
124
- user: user,
125
- message_id: result.dig('messages', 0, 'id'),
126
- message_type: 'order_status_update',
127
- phone_number: user.phone_number,
128
- messageable: order
129
- )
130
-
131
- Rails.logger.info "Order status update sent for order #{order.id}: #{order.status}"
132
- end
133
-
134
- rescue KapsoClientRuby::Error => e
135
- Rails.logger.error "Failed to send order status update for order #{order.id}: #{e.message}"
136
- raise
137
- end
138
- end
139
-
140
- private
141
-
142
- def build_order_status_components(order, user)
143
- [
144
- {
145
- type: 'body',
146
- parameters: [
147
- { type: 'text', text: user.first_name || 'Customer' },
148
- { type: 'text', text: order.id.to_s },
149
- { type: 'text', text: order.status.humanize },
150
- { type: 'text', text: order.formatted_total }
151
- ]
152
- }
153
- ].tap do |components|
154
- # Add tracking info for shipped orders
155
- if order.shipped? && order.tracking_number.present?
156
- components << {
157
- type: 'body',
158
- parameters: [
159
- { type: 'text', text: order.tracking_number }
160
- ]
161
- }
162
- end
163
- end
164
- end
165
- end
166
-
167
- class SendPhoneVerificationJob < ApplicationJob
168
- queue_as :whatsapp_messages
169
-
170
- retry_on KapsoClientRuby::Error, wait: 30.seconds, attempts: 3
171
-
172
- def perform(user)
173
- return unless user.phone_number.present?
174
-
175
- # Generate verification code
176
- verification_code = rand(100000..999999).to_s
177
-
178
- # Store verification code (you might use Redis or database)
179
- Rails.cache.write("phone_verification:#{user.id}", verification_code, expires_in: 10.minutes)
180
-
181
- service = KapsoClientRuby::Rails::Service.new
182
-
183
- begin
184
- result = service.send_template_message(
185
- to: user.phone_number,
186
- template_name: 'phone_verification',
187
- language: user.preferred_language || 'en',
188
- components: [
189
- {
190
- type: 'body',
191
- parameters: [
192
- { type: 'text', text: verification_code }
193
- ]
194
- }
195
- ]
196
- )
197
-
198
- if result && result.dig('messages', 0, 'id')
199
- WhatsappMessage.track_message(
200
- user: user,
201
- message_id: result.dig('messages', 0, 'id'),
202
- message_type: 'phone_verification',
203
- phone_number: user.phone_number,
204
- messageable: user
205
- )
206
-
207
- Rails.logger.info "Phone verification sent to user #{user.id}"
208
- end
209
-
210
- rescue KapsoClientRuby::Error => e
211
- Rails.logger.error "Failed to send phone verification to user #{user.id}: #{e.message}"
212
- raise
213
- end
214
- end
215
- end
216
-
217
- class SendNotificationJob < ApplicationJob
218
- queue_as :whatsapp_messages
219
-
220
- retry_on KapsoClientRuby::RateLimitError, wait: :exponentially_longer, attempts: 3
221
-
222
- def perform(user, message, message_type = 'general_notification')
223
- return unless user.phone_number.present? && user.notifications_enabled?
224
-
225
- service = KapsoMessageService.new
226
-
227
- begin
228
- result = service.send_text(
229
- phone_number: user.phone_number,
230
- message: message
231
- )
232
-
233
- if result && result.dig('messages', 0, 'id')
234
- WhatsappMessage.track_message(
235
- user: user,
236
- message_id: result.dig('messages', 0, 'id'),
237
- message_type: message_type,
238
- phone_number: user.phone_number
239
- )
240
-
241
- Rails.logger.info "Notification sent to user #{user.id}: #{message.truncate(50)}"
242
- end
243
-
244
- rescue KapsoClientRuby::Error => e
245
- Rails.logger.error "Failed to send notification to user #{user.id}: #{e.message}"
246
- raise
247
- end
248
- end
249
- end
250
-
251
- class SendBulkNotificationJob < ApplicationJob
252
- queue_as :bulk_whatsapp
253
-
254
- # Process users in batches to avoid overwhelming the API
255
- def perform(user_ids, message, message_type = 'marketing')
256
- User.where(id: user_ids).with_phone_number.opted_in_for_notifications.find_each(batch_size: 50) do |user|
257
- # Add delay between messages to respect rate limits
258
- SendNotificationJob.set(wait: rand(1..5).seconds).perform_later(user, message, message_type)
259
- end
260
- end
261
- end
262
-
263
- class HandleIncomingMessageJob < ApplicationJob
264
- queue_as :whatsapp_webhooks
265
-
266
- def perform(message_data)
267
- phone_number = message_data['from']
268
- message_text = message_data.dig('text', 'body')
269
- message_id = message_data['id']
270
-
271
- # Find user by phone number
272
- user = User.find_by(phone_number: phone_number)
273
-
274
- unless user
275
- Rails.logger.warn "Received message from unknown number: #{phone_number}"
276
- return
277
- end
278
-
279
- Rails.logger.info "Received message from user #{user.id}: #{message_text}"
280
-
281
- # Process the incoming message based on content
282
- case message_text&.downcase&.strip
283
- when 'stop', 'unsubscribe'
284
- handle_unsubscribe_request(user)
285
- when 'start', 'subscribe'
286
- handle_subscribe_request(user)
287
- when 'help', 'menu'
288
- send_help_message(user)
289
- when 'status'
290
- send_account_status(user)
291
- else
292
- # Forward to customer service or handle as general inquiry
293
- handle_general_inquiry(user, message_text, message_id)
294
- end
295
- end
296
-
297
- private
298
-
299
- def handle_unsubscribe_request(user)
300
- user.update!(notifications_enabled: false)
301
-
302
- service = KapsoMessageService.new
303
- service.send_text(
304
- phone_number: user.phone_number,
305
- message: "You have been unsubscribed from notifications. Reply 'START' to re-enable."
306
- )
307
-
308
- Rails.logger.info "User #{user.id} unsubscribed from notifications"
309
- end
310
-
311
- def handle_subscribe_request(user)
312
- user.update!(notifications_enabled: true)
313
-
314
- service = KapsoMessageService.new
315
- service.send_text(
316
- phone_number: user.phone_number,
317
- message: "Welcome back! You'll now receive notifications. Reply 'STOP' to unsubscribe."
318
- )
319
-
320
- Rails.logger.info "User #{user.id} subscribed to notifications"
321
- end
322
-
323
- def send_help_message(user)
324
- help_text = <<~TEXT
325
- Available commands:
326
- • STOP - Unsubscribe from messages
327
- • START - Subscribe to messages
328
- • STATUS - Check your account status
329
- • HELP - Show this menu
330
-
331
- For support, contact us at support@example.com
332
- TEXT
333
-
334
- service = KapsoMessageService.new
335
- service.send_text(phone_number: user.phone_number, message: help_text)
336
- end
337
-
338
- def send_account_status(user)
339
- recent_orders = user.orders.recent.limit(3)
340
-
341
- status_text = "Account Status:\n"
342
- status_text += "Name: #{user.name}\n"
343
- status_text += "Email: #{user.email}\n"
344
- status_text += "Recent orders: #{recent_orders.count}\n"
345
-
346
- if recent_orders.any?
347
- status_text += "\nLast order: ##{recent_orders.first.id} - #{recent_orders.first.status.humanize}"
348
- end
349
-
350
- service = KapsoMessageService.new
351
- service.send_text(phone_number: user.phone_number, message: status_text)
352
- end
353
-
354
- def handle_general_inquiry(user, message_text, message_id)
355
- # Create a support ticket or notification for customer service
356
- SupportTicket.create!(
357
- user: user,
358
- subject: "WhatsApp Inquiry",
359
- message: message_text,
360
- source: 'whatsapp',
361
- whatsapp_message_id: message_id
362
- )
363
-
364
- # Send auto-reply
365
- service = KapsoMessageService.new
366
- service.send_text(
367
- phone_number: user.phone_number,
368
- message: "Thanks for your message! Our team will get back to you soon. For urgent matters, call us at (555) 123-4567."
369
- )
370
-
371
- Rails.logger.info "Created support ticket for user #{user.id} from WhatsApp message"
372
- end
373
- end
374
-
375
- class UpdateMessageStatusJob < ApplicationJob
376
- queue_as :whatsapp_webhooks
377
-
378
- def perform(status_data)
379
- message_id = status_data['id']
380
- status = status_data['status']
381
- timestamp = status_data['timestamp']
382
-
383
- # Update message status in database
384
- WhatsappMessage.update_status_from_webhook(message_id, status, timestamp)
385
-
386
- Rails.logger.debug "Updated message #{message_id} status to #{status}"
387
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Background jobs for WhatsApp message sending
4
+ # These jobs handle asynchronous message sending to improve performance
5
+
6
+ class SendWelcomeMessageJob < ApplicationJob
7
+ queue_as :whatsapp_messages
8
+
9
+ retry_on KapsoClientRuby::RateLimitError, wait: :exponentially_longer, attempts: 5
10
+ retry_on KapsoClientRuby::TemporaryError, wait: 30.seconds, attempts: 3
11
+
12
+ discard_on KapsoClientRuby::AuthenticationError
13
+ discard_on KapsoClientRuby::ValidationError
14
+
15
+ def perform(user)
16
+ return unless user.phone_number.present?
17
+
18
+ service = KapsoMessageService.new
19
+
20
+ begin
21
+ result = service.send_welcome_message(user)
22
+
23
+ if result && result.dig('messages', 0, 'id')
24
+ # Track the message
25
+ WhatsappMessage.track_message(
26
+ user: user,
27
+ message_id: result.dig('messages', 0, 'id'),
28
+ message_type: 'welcome',
29
+ phone_number: user.phone_number,
30
+ messageable: user
31
+ )
32
+
33
+ Rails.logger.info "Welcome message sent to user #{user.id}: #{result.dig('messages', 0, 'id')}"
34
+ end
35
+
36
+ rescue KapsoClientRuby::Error => e
37
+ Rails.logger.error "Failed to send welcome message to user #{user.id}: #{e.message}"
38
+
39
+ # Track failed message
40
+ WhatsappMessage.create!(
41
+ user: user,
42
+ message_id: "failed_#{SecureRandom.hex(8)}",
43
+ message_type: 'welcome',
44
+ phone_number: user.phone_number,
45
+ messageable: user,
46
+ status: 'failed',
47
+ error_message: e.message,
48
+ sent_at: Time.current
49
+ )
50
+
51
+ raise # Re-raise to trigger retry logic
52
+ end
53
+ end
54
+ end
55
+
56
+ class SendOrderConfirmationJob < ApplicationJob
57
+ queue_as :whatsapp_messages
58
+
59
+ retry_on KapsoClientRuby::RateLimitError, wait: :exponentially_longer, attempts: 5
60
+ retry_on KapsoClientRuby::TemporaryError, wait: 30.seconds, attempts: 3
61
+
62
+ def perform(user, order)
63
+ return unless user.phone_number.present?
64
+
65
+ service = KapsoMessageService.new
66
+
67
+ begin
68
+ result = service.send_order_confirmation(order)
69
+
70
+ if result && result.dig('messages', 0, 'id')
71
+ WhatsappMessage.track_message(
72
+ user: user,
73
+ message_id: result.dig('messages', 0, 'id'),
74
+ message_type: 'order_confirmation',
75
+ phone_number: user.phone_number,
76
+ messageable: order
77
+ )
78
+
79
+ Rails.logger.info "Order confirmation sent for order #{order.id}: #{result.dig('messages', 0, 'id')}"
80
+ end
81
+
82
+ rescue KapsoClientRuby::Error => e
83
+ Rails.logger.error "Failed to send order confirmation for order #{order.id}: #{e.message}"
84
+ raise
85
+ end
86
+ end
87
+ end
88
+
89
+ class SendOrderStatusUpdateJob < ApplicationJob
90
+ queue_as :whatsapp_messages
91
+
92
+ retry_on KapsoClientRuby::RateLimitError, wait: :exponentially_longer, attempts: 5
93
+
94
+ def perform(user, order)
95
+ return unless user.phone_number.present?
96
+
97
+ # Don't spam users with too many updates
98
+ return if user.received_message_type_recently?('order_status_update', within: 1.hour)
99
+
100
+ service = KapsoClientRuby::Rails::Service.new
101
+
102
+ begin
103
+ # Use different templates based on order status
104
+ template_name = case order.status
105
+ when 'confirmed' then 'order_confirmed'
106
+ when 'processing' then 'order_processing'
107
+ when 'shipped' then 'order_shipped'
108
+ when 'delivered' then 'order_delivered'
109
+ when 'cancelled' then 'order_cancelled'
110
+ else 'order_status_update'
111
+ end
112
+
113
+ components = build_order_status_components(order, user)
114
+
115
+ result = service.send_template_message(
116
+ to: user.phone_number,
117
+ template_name: template_name,
118
+ language: user.preferred_language || 'en',
119
+ components: components
120
+ )
121
+
122
+ if result && result.dig('messages', 0, 'id')
123
+ WhatsappMessage.track_message(
124
+ user: user,
125
+ message_id: result.dig('messages', 0, 'id'),
126
+ message_type: 'order_status_update',
127
+ phone_number: user.phone_number,
128
+ messageable: order
129
+ )
130
+
131
+ Rails.logger.info "Order status update sent for order #{order.id}: #{order.status}"
132
+ end
133
+
134
+ rescue KapsoClientRuby::Error => e
135
+ Rails.logger.error "Failed to send order status update for order #{order.id}: #{e.message}"
136
+ raise
137
+ end
138
+ end
139
+
140
+ private
141
+
142
+ def build_order_status_components(order, user)
143
+ [
144
+ {
145
+ type: 'body',
146
+ parameters: [
147
+ { type: 'text', text: user.first_name || 'Customer' },
148
+ { type: 'text', text: order.id.to_s },
149
+ { type: 'text', text: order.status.humanize },
150
+ { type: 'text', text: order.formatted_total }
151
+ ]
152
+ }
153
+ ].tap do |components|
154
+ # Add tracking info for shipped orders
155
+ if order.shipped? && order.tracking_number.present?
156
+ components << {
157
+ type: 'body',
158
+ parameters: [
159
+ { type: 'text', text: order.tracking_number }
160
+ ]
161
+ }
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ class SendPhoneVerificationJob < ApplicationJob
168
+ queue_as :whatsapp_messages
169
+
170
+ retry_on KapsoClientRuby::Error, wait: 30.seconds, attempts: 3
171
+
172
+ def perform(user)
173
+ return unless user.phone_number.present?
174
+
175
+ # Generate verification code
176
+ verification_code = rand(100000..999999).to_s
177
+
178
+ # Store verification code (you might use Redis or database)
179
+ Rails.cache.write("phone_verification:#{user.id}", verification_code, expires_in: 10.minutes)
180
+
181
+ service = KapsoClientRuby::Rails::Service.new
182
+
183
+ begin
184
+ result = service.send_template_message(
185
+ to: user.phone_number,
186
+ template_name: 'phone_verification',
187
+ language: user.preferred_language || 'en',
188
+ components: [
189
+ {
190
+ type: 'body',
191
+ parameters: [
192
+ { type: 'text', text: verification_code }
193
+ ]
194
+ }
195
+ ]
196
+ )
197
+
198
+ if result && result.dig('messages', 0, 'id')
199
+ WhatsappMessage.track_message(
200
+ user: user,
201
+ message_id: result.dig('messages', 0, 'id'),
202
+ message_type: 'phone_verification',
203
+ phone_number: user.phone_number,
204
+ messageable: user
205
+ )
206
+
207
+ Rails.logger.info "Phone verification sent to user #{user.id}"
208
+ end
209
+
210
+ rescue KapsoClientRuby::Error => e
211
+ Rails.logger.error "Failed to send phone verification to user #{user.id}: #{e.message}"
212
+ raise
213
+ end
214
+ end
215
+ end
216
+
217
+ class SendNotificationJob < ApplicationJob
218
+ queue_as :whatsapp_messages
219
+
220
+ retry_on KapsoClientRuby::RateLimitError, wait: :exponentially_longer, attempts: 3
221
+
222
+ def perform(user, message, message_type = 'general_notification')
223
+ return unless user.phone_number.present? && user.notifications_enabled?
224
+
225
+ service = KapsoMessageService.new
226
+
227
+ begin
228
+ result = service.send_text(
229
+ phone_number: user.phone_number,
230
+ message: message
231
+ )
232
+
233
+ if result && result.dig('messages', 0, 'id')
234
+ WhatsappMessage.track_message(
235
+ user: user,
236
+ message_id: result.dig('messages', 0, 'id'),
237
+ message_type: message_type,
238
+ phone_number: user.phone_number
239
+ )
240
+
241
+ Rails.logger.info "Notification sent to user #{user.id}: #{message.truncate(50)}"
242
+ end
243
+
244
+ rescue KapsoClientRuby::Error => e
245
+ Rails.logger.error "Failed to send notification to user #{user.id}: #{e.message}"
246
+ raise
247
+ end
248
+ end
249
+ end
250
+
251
+ class SendBulkNotificationJob < ApplicationJob
252
+ queue_as :bulk_whatsapp
253
+
254
+ # Process users in batches to avoid overwhelming the API
255
+ def perform(user_ids, message, message_type = 'marketing')
256
+ User.where(id: user_ids).with_phone_number.opted_in_for_notifications.find_each(batch_size: 50) do |user|
257
+ # Add delay between messages to respect rate limits
258
+ SendNotificationJob.set(wait: rand(1..5).seconds).perform_later(user, message, message_type)
259
+ end
260
+ end
261
+ end
262
+
263
+ class HandleIncomingMessageJob < ApplicationJob
264
+ queue_as :whatsapp_webhooks
265
+
266
+ def perform(message_data)
267
+ phone_number = message_data['from']
268
+ message_text = message_data.dig('text', 'body')
269
+ message_id = message_data['id']
270
+
271
+ # Find user by phone number
272
+ user = User.find_by(phone_number: phone_number)
273
+
274
+ unless user
275
+ Rails.logger.warn "Received message from unknown number: #{phone_number}"
276
+ return
277
+ end
278
+
279
+ Rails.logger.info "Received message from user #{user.id}: #{message_text}"
280
+
281
+ # Process the incoming message based on content
282
+ case message_text&.downcase&.strip
283
+ when 'stop', 'unsubscribe'
284
+ handle_unsubscribe_request(user)
285
+ when 'start', 'subscribe'
286
+ handle_subscribe_request(user)
287
+ when 'help', 'menu'
288
+ send_help_message(user)
289
+ when 'status'
290
+ send_account_status(user)
291
+ else
292
+ # Forward to customer service or handle as general inquiry
293
+ handle_general_inquiry(user, message_text, message_id)
294
+ end
295
+ end
296
+
297
+ private
298
+
299
+ def handle_unsubscribe_request(user)
300
+ user.update!(notifications_enabled: false)
301
+
302
+ service = KapsoMessageService.new
303
+ service.send_text(
304
+ phone_number: user.phone_number,
305
+ message: "You have been unsubscribed from notifications. Reply 'START' to re-enable."
306
+ )
307
+
308
+ Rails.logger.info "User #{user.id} unsubscribed from notifications"
309
+ end
310
+
311
+ def handle_subscribe_request(user)
312
+ user.update!(notifications_enabled: true)
313
+
314
+ service = KapsoMessageService.new
315
+ service.send_text(
316
+ phone_number: user.phone_number,
317
+ message: "Welcome back! You'll now receive notifications. Reply 'STOP' to unsubscribe."
318
+ )
319
+
320
+ Rails.logger.info "User #{user.id} subscribed to notifications"
321
+ end
322
+
323
+ def send_help_message(user)
324
+ help_text = <<~TEXT
325
+ Available commands:
326
+ • STOP - Unsubscribe from messages
327
+ • START - Subscribe to messages
328
+ • STATUS - Check your account status
329
+ • HELP - Show this menu
330
+
331
+ For support, contact us at support@example.com
332
+ TEXT
333
+
334
+ service = KapsoMessageService.new
335
+ service.send_text(phone_number: user.phone_number, message: help_text)
336
+ end
337
+
338
+ def send_account_status(user)
339
+ recent_orders = user.orders.recent.limit(3)
340
+
341
+ status_text = "Account Status:\n"
342
+ status_text += "Name: #{user.name}\n"
343
+ status_text += "Email: #{user.email}\n"
344
+ status_text += "Recent orders: #{recent_orders.count}\n"
345
+
346
+ if recent_orders.any?
347
+ status_text += "\nLast order: ##{recent_orders.first.id} - #{recent_orders.first.status.humanize}"
348
+ end
349
+
350
+ service = KapsoMessageService.new
351
+ service.send_text(phone_number: user.phone_number, message: status_text)
352
+ end
353
+
354
+ def handle_general_inquiry(user, message_text, message_id)
355
+ # Create a support ticket or notification for customer service
356
+ SupportTicket.create!(
357
+ user: user,
358
+ subject: "WhatsApp Inquiry",
359
+ message: message_text,
360
+ source: 'whatsapp',
361
+ whatsapp_message_id: message_id
362
+ )
363
+
364
+ # Send auto-reply
365
+ service = KapsoMessageService.new
366
+ service.send_text(
367
+ phone_number: user.phone_number,
368
+ message: "Thanks for your message! Our team will get back to you soon. For urgent matters, call us at (555) 123-4567."
369
+ )
370
+
371
+ Rails.logger.info "Created support ticket for user #{user.id} from WhatsApp message"
372
+ end
373
+ end
374
+
375
+ class UpdateMessageStatusJob < ApplicationJob
376
+ queue_as :whatsapp_webhooks
377
+
378
+ def perform(status_data)
379
+ message_id = status_data['id']
380
+ status = status_data['status']
381
+ timestamp = status_data['timestamp']
382
+
383
+ # Update message status in database
384
+ WhatsappMessage.update_status_from_webhook(message_id, status, timestamp)
385
+
386
+ Rails.logger.debug "Updated message #{message_id} status to #{status}"
387
+ end
388
388
  end