770 lines
17 KiB
Markdown
770 lines
17 KiB
Markdown
# WhatsApp Integration & Payment Reminders - Usage Guide
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### 1. Install Dependencies
|
|
```bash
|
|
cd backend
|
|
npm install
|
|
```
|
|
|
|
This installs:
|
|
- `node-cron@^3.0.3` - Scheduled reminders
|
|
- `moment-timezone@^0.5.43` - Date/time handling
|
|
|
|
### 2. Start Server
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
You should see:
|
|
```
|
|
⏰ Starting payment reminder scheduler...
|
|
Payment reminder scheduler started (9:00 AM IST daily)
|
|
🚀 Server running on port 3000
|
|
📱 WhatsApp share: http://localhost:3000/api/share
|
|
🔔 Notifications: http://localhost:3000/api/notifications
|
|
```
|
|
|
|
---
|
|
|
|
## 📱 **How to Use WhatsApp Sharing**
|
|
|
|
### Example 1: Share Payment Receipt (After Payment)
|
|
|
|
**Scenario:** Member just made a payment, wants to share receipt
|
|
|
|
#### Backend:
|
|
```javascript
|
|
// In your payment controller, after recording payment
|
|
const payment = await Payment.create({...});
|
|
|
|
// Send notification to member
|
|
const WhatsAppHelper = require('../utils/whatsapp-helper');
|
|
const message = WhatsAppHelper.generatePaymentReceipt(
|
|
payment,
|
|
group,
|
|
member
|
|
);
|
|
|
|
await Notification.create({
|
|
type: 'payment_confirmation',
|
|
user_id: member.id,
|
|
group_id: group.id,
|
|
payment_id: payment.id,
|
|
channel: 'whatsapp',
|
|
message: message,
|
|
status: 'sent'
|
|
});
|
|
```
|
|
|
|
#### Flutter:
|
|
```dart
|
|
// In payment success dialog
|
|
import '../../core/utils/whatsapp_util.dart';
|
|
import '../../shared/widgets/payment_success_dialog.dart';
|
|
|
|
// After payment recorded
|
|
PaymentSuccessDialog.show(
|
|
context,
|
|
paymentId: payment.id,
|
|
amount: 5000,
|
|
groupName: 'Family Chit Fund',
|
|
transactionId: 'TXN123456',
|
|
paymentDate: DateTime.now(),
|
|
paymentMethod: 'UPI',
|
|
);
|
|
|
|
// Or manually trigger share
|
|
await WhatsAppUtil.sharePaymentReceipt(paymentId);
|
|
```
|
|
|
|
---
|
|
|
|
### Example 2: Share Draw Result (After Draw Completion)
|
|
|
|
**Scenario:** Manager completed a draw, wants to announce winner
|
|
|
|
#### Backend:
|
|
```javascript
|
|
// After draw completion
|
|
const draw = await MonthlyDraw.create({...});
|
|
|
|
// Generate share link
|
|
const message = WhatsAppHelper.generateDrawResult(
|
|
group,
|
|
winner,
|
|
prizeAmount,
|
|
month,
|
|
totalMembers
|
|
);
|
|
|
|
const whatsappUrl = WhatsAppHelper.generateShareLink(
|
|
winner.mobile_number,
|
|
message
|
|
);
|
|
|
|
// Send to winner
|
|
await Notification.create({
|
|
type: 'draw_result',
|
|
user_id: winner.id,
|
|
group_id: group.id,
|
|
draw_id: draw.id,
|
|
channel: 'whatsapp',
|
|
message: message,
|
|
status: 'sent'
|
|
});
|
|
```
|
|
|
|
#### Flutter:
|
|
```dart
|
|
// In draw results screen
|
|
import '../../core/utils/whatsapp_util.dart';
|
|
import '../../shared/widgets/whatsapp_share_button.dart';
|
|
|
|
// After draw completion
|
|
WhatsAppShareButton(
|
|
label: 'Share Results',
|
|
onPressed: () async {
|
|
await WhatsAppUtil.shareDrawResult(draw.id);
|
|
},
|
|
)
|
|
|
|
// Or open share options sheet
|
|
WhatsAppShareSheet.show(
|
|
context,
|
|
[
|
|
WhatsAppShareOption(
|
|
title: 'Share with Winner',
|
|
icon: Icons.emoji_events,
|
|
color: Colors.green.shade600,
|
|
onTap: () => WhatsAppUtil.shareDrawResult(draw.id),
|
|
),
|
|
WhatsAppShareOption(
|
|
title: 'Share with All Members',
|
|
icon: Icons.group,
|
|
color: Colors.blue.shade600,
|
|
onTap: () => shareWithAllMembers(),
|
|
),
|
|
],
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
### Example 3: Invite New Member
|
|
|
|
**Scenario:** Manager wants to invite someone to join group
|
|
|
|
#### Backend API Call:
|
|
```bash
|
|
POST /api/share/group-invite
|
|
Authorization: Bearer <manager-token>
|
|
|
|
{
|
|
"groupId": "group-uuid",
|
|
"recipientPhone": "9876543210"
|
|
}
|
|
```
|
|
|
|
#### Flutter:
|
|
```dart
|
|
// In group details page or add member dialog
|
|
TextFormField(
|
|
controller: phoneController,
|
|
decoration: InputDecoration(labelText: 'Phone Number'),
|
|
)
|
|
|
|
WhatsAppShareButton(
|
|
label: 'Send Invitation',
|
|
onPressed: () async {
|
|
await WhatsAppUtil.shareGroupInvite(
|
|
groupId,
|
|
phoneController.text,
|
|
);
|
|
},
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
### Example 4: Manual Payment Reminder
|
|
|
|
**Scenario:** Manager wants to remind specific member
|
|
|
|
#### Flutter:
|
|
```dart
|
|
// In member list, add action button
|
|
IconButton(
|
|
icon: Icon(Icons.whatsapp, color: Color(0xFF25D366)),
|
|
onPressed: () async {
|
|
await WhatsAppUtil.sendPaymentReminder(groupId, memberId);
|
|
},
|
|
tooltip: 'Send WhatsApp Reminder',
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
### Example 5: Bulk Reminders
|
|
|
|
**Scenario:** Manager wants to remind all unpaid members
|
|
|
|
#### Flutter:
|
|
```dart
|
|
// In group details page
|
|
ElevatedButton.icon(
|
|
icon: Icon(Icons.send_rounded),
|
|
label: Text('Send Reminders to All'),
|
|
onPressed: () async {
|
|
final result = await WhatsAppUtil.sendBulkReminders(groupId);
|
|
|
|
if (result != null) {
|
|
final count = result['total_reminders'];
|
|
showDialog(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: Text('$count Reminders Generated'),
|
|
content: Text('Open WhatsApp for each member?'),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
child: Text('Later'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
// Open each WhatsApp link
|
|
// (User will need to manually send each)
|
|
},
|
|
child: Text('Yes, Open'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
},
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## ⏰ **Payment Reminder Schedule**
|
|
|
|
### Automatic Reminders:
|
|
|
|
The system automatically sends reminders at:
|
|
|
|
| Days Before/After Due | Type | Urgency |
|
|
|----------------------|------|---------|
|
|
| 7 days before | Upcoming payment | ⏰ Low |
|
|
| 3 days before | Payment due soon | ⏰ Medium |
|
|
| 1 day before | Payment due tomorrow | ⚠️ High |
|
|
| 0 (On due date) | Payment due today | ⚠️ High |
|
|
| 1 day overdue | Payment overdue | 🚨 Urgent |
|
|
| 3 days overdue | Still overdue | 🚨 Urgent |
|
|
| 7 days overdue | Seriously overdue | 🚨 Critical |
|
|
| 14 days overdue | Very seriously overdue | 🚨 Critical |
|
|
| 30 days overdue | Final reminder | 🚨 Critical |
|
|
|
|
### Reminder Logic:
|
|
|
|
```
|
|
For each active group:
|
|
Calculate current month
|
|
Calculate due date (start_date + months + draw_date)
|
|
Get days until due
|
|
|
|
If (days until due) in [7, 3, 1, 0]:
|
|
For each member who hasn't paid:
|
|
Create reminder notification
|
|
Log in database
|
|
|
|
If overdue (days < 0):
|
|
If days overdue in [1, 3, 7, 14, 30]:
|
|
For each member who hasn't paid:
|
|
Create URGENT reminder
|
|
Log in database
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 **Notification Types**
|
|
|
|
### Payment Related:
|
|
- `payment_reminder` - Regular reminder (7, 3, 1, 0 days before)
|
|
- `payment_overdue` - Overdue payment (1, 3, 7, 14, 30 days after)
|
|
- `payment_confirmation` - Payment received successfully
|
|
|
|
### Draw Related:
|
|
- `draw_result` - Draw completed, winner announced
|
|
|
|
### Member Related:
|
|
- `member_joined` - New member added to group
|
|
- `member_removed` - Member removed from group
|
|
- `welcome_message` - Welcome new member
|
|
|
|
### Group Related:
|
|
- `group_invite` - Invitation to join group
|
|
- `group_started` - Group moved from forming to active
|
|
- `group_completed` - Group completed all months
|
|
|
|
### System:
|
|
- `manager_notification` - Important manager notifications
|
|
- `system_alert` - Critical system alerts
|
|
|
|
---
|
|
|
|
## 🧪 **Testing Guide**
|
|
|
|
### Test 1: Manual Reminder Trigger
|
|
|
|
```bash
|
|
# Create test script: backend/test-reminders.js
|
|
|
|
const ReminderService = require('./src/services/reminder-service');
|
|
|
|
(async () => {
|
|
console.log('Testing manual reminders...');
|
|
const result = await ReminderService.triggerManualReminders();
|
|
console.log(`Sent ${result} reminders`);
|
|
process.exit(0);
|
|
})();
|
|
|
|
# Run it:
|
|
node test-reminders.js
|
|
```
|
|
|
|
### Test 2: Share Payment Receipt
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/share/payment-receipt \
|
|
-H "Authorization: Bearer YOUR_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"paymentId": "your-payment-id"}'
|
|
```
|
|
|
|
### Test 3: Get Notifications
|
|
|
|
```bash
|
|
curl -X GET http://localhost:3000/api/notifications \
|
|
-H "Authorization: Bearer YOUR_TOKEN"
|
|
```
|
|
|
|
### Test 4: Get Unread Count
|
|
|
|
```bash
|
|
curl -X GET http://localhost:3000/api/notifications/unread-count \
|
|
-H "Authorization: Bearer YOUR_TOKEN"
|
|
```
|
|
|
|
---
|
|
|
|
## 📱 **Flutter Integration Examples**
|
|
|
|
### Add to Payment Recording Dialog
|
|
|
|
```dart
|
|
// After payment is recorded successfully
|
|
|
|
final payment = await recordPayment(...);
|
|
|
|
if (payment != null) {
|
|
// Show success dialog with WhatsApp share
|
|
await PaymentSuccessDialog.show(
|
|
context,
|
|
paymentId: payment.id,
|
|
amount: payment.amount,
|
|
groupName: group.name,
|
|
transactionId: payment.transactionId,
|
|
paymentDate: payment.paymentDate,
|
|
paymentMethod: payment.paymentMethod,
|
|
);
|
|
}
|
|
```
|
|
|
|
### Add to Draw Results Screen
|
|
|
|
```dart
|
|
// After draw completion
|
|
|
|
WhatsAppShareButton(
|
|
label: 'Share Results on WhatsApp',
|
|
onPressed: () async {
|
|
await WhatsAppUtil.shareDrawResult(draw.id);
|
|
},
|
|
)
|
|
```
|
|
|
|
### Add to Member List (Manager)
|
|
|
|
```dart
|
|
// In member card actions
|
|
Row(
|
|
children: [
|
|
WhatsAppIconButton(
|
|
onPressed: () async {
|
|
await WhatsAppUtil.sendPaymentReminder(
|
|
groupId,
|
|
member.id,
|
|
);
|
|
},
|
|
tooltip: 'Send Reminder',
|
|
),
|
|
// Other actions...
|
|
],
|
|
)
|
|
```
|
|
|
|
### Add Notifications to Bottom Nav
|
|
|
|
```dart
|
|
BottomNavigationBar(
|
|
items: [
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.home),
|
|
label: 'Home',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Obx(() => NotificationBadge(
|
|
count: NotificationService.to.unreadCount.value,
|
|
child: Icon(Icons.notifications),
|
|
)),
|
|
label: 'Notifications',
|
|
),
|
|
// Other items...
|
|
],
|
|
onTap: (index) {
|
|
if (index == 1) {
|
|
Get.to(() => NotificationCenterPage());
|
|
}
|
|
},
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## 🔔 **Notification Center Features**
|
|
|
|
### Features Implemented:
|
|
- ✅ List all notifications
|
|
- ✅ Show unread count badge
|
|
- ✅ Mark as read on tap
|
|
- ✅ Mark all as read
|
|
- ✅ Swipe to delete
|
|
- ✅ Pull to refresh
|
|
- ✅ Infinite scroll pagination
|
|
- ✅ Filter by type/status
|
|
- ✅ Empty state when no notifications
|
|
- ✅ Skeleton loader while loading
|
|
|
|
### Usage:
|
|
```dart
|
|
// Navigate to notification center
|
|
Get.to(() => NotificationCenterPage());
|
|
|
|
// Check unread count
|
|
final count = NotificationService.to.unreadCount.value;
|
|
|
|
// Refresh notifications
|
|
await NotificationService.to.refresh();
|
|
|
|
// Mark all as read
|
|
await NotificationService.to.markAllAsRead();
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 **Common Use Cases**
|
|
|
|
### Use Case 1: New Member Joins
|
|
```dart
|
|
// In add member success callback
|
|
await Notification.create({
|
|
type: 'member_joined',
|
|
user_id: managerId,
|
|
group_id: groupId,
|
|
channel: 'in_app',
|
|
message: '${memberName} joined ${groupName}',
|
|
});
|
|
|
|
// Optionally send welcome WhatsApp to new member
|
|
final welcomeMsg = WhatsAppHelper.generateWelcomeMessage(
|
|
member,
|
|
group,
|
|
manager
|
|
);
|
|
await openWhatsApp(member.phone, welcomeMsg);
|
|
```
|
|
|
|
### Use Case 2: Manager Wants Quick Reminder
|
|
|
|
```dart
|
|
// Add quick action in group details
|
|
QuickActionCard(
|
|
title: 'Send Payment Reminders',
|
|
subtitle: 'Remind unpaid members',
|
|
icon: Icons.send,
|
|
color: Colors.orange.shade600,
|
|
onTap: () async {
|
|
final result = await WhatsAppUtil.sendBulkReminders(groupId);
|
|
|
|
if (result != null) {
|
|
final count = result['total_reminders'];
|
|
SnackbarUtil.showSuccess('$count reminders generated!');
|
|
}
|
|
},
|
|
)
|
|
```
|
|
|
|
### Use Case 3: Member Views Notifications
|
|
|
|
```dart
|
|
// Member dashboard - show recent notifications
|
|
Obx(() {
|
|
final recentNotifications = NotificationService.to
|
|
.notifications
|
|
.take(3)
|
|
.toList();
|
|
|
|
return Column(
|
|
children: recentNotifications.map((n) =>
|
|
ListTile(
|
|
leading: Icon(n.getIcon(), color: n.getColor()),
|
|
title: Text(n.title),
|
|
subtitle: Text(n.message, maxLines: 1),
|
|
trailing: Text(n.getTimeAgo()),
|
|
onTap: () => Get.to(() => NotificationCenterPage()),
|
|
)
|
|
).toList(),
|
|
);
|
|
})
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 **Scheduler Configuration**
|
|
|
|
### Current Schedule:
|
|
- **Time:** 9:00 AM IST daily
|
|
- **Timezone:** Asia/Kolkata
|
|
- **Cron:** `'0 9 * * *'`
|
|
|
|
### Customize Schedule:
|
|
|
|
```javascript
|
|
// In reminder-service.js
|
|
|
|
// Run every hour
|
|
cron.schedule('0 * * * *', async () => { ... });
|
|
|
|
// Run twice daily (9 AM and 6 PM)
|
|
cron.schedule('0 9,18 * * *', async () => { ... });
|
|
|
|
// Run every Monday at 9 AM
|
|
cron.schedule('0 9 * * 1', async () => { ... });
|
|
|
|
// Multiple schedules
|
|
cron.schedule('0 9 * * *', () => sendMorningReminders());
|
|
cron.schedule('0 18 * * *', () => sendEveningReminders());
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 **Monitoring & Analytics**
|
|
|
|
### Get Reminder Statistics:
|
|
|
|
```javascript
|
|
const stats = await ReminderService.getReminderStats(groupId, 30);
|
|
|
|
console.log(stats);
|
|
// {
|
|
// total: 150,
|
|
// sent: 145,
|
|
// failed: 5,
|
|
// success_rate: "96.67"
|
|
// }
|
|
```
|
|
|
|
### Get Upcoming Reminders (Preview):
|
|
|
|
```javascript
|
|
const upcoming = await ReminderService.getUpcomingReminders(groupId);
|
|
|
|
console.log(upcoming);
|
|
// {
|
|
// group_name: "Family Chit Fund",
|
|
// current_month: 5,
|
|
// due_date: "08 Nov 2025",
|
|
// days_until_due: 3,
|
|
// unpaid_members: 8,
|
|
// unpaid_member_list: [...]
|
|
// }
|
|
```
|
|
|
|
---
|
|
|
|
## 🎨 **Message Customization**
|
|
|
|
### Customize WhatsApp Messages:
|
|
|
|
Edit `backend/src/utils/whatsapp-helper.js`:
|
|
|
|
```javascript
|
|
// Example: Add company branding
|
|
static generatePaymentReceipt(payment, group, member) {
|
|
return `🎉 *Payment Successful!*\n\n` +
|
|
`👤 Name: ${member.full_name}\n` +
|
|
`🏦 Group: ${group.name}\n` +
|
|
`💰 Amount: ${this.formatCurrency(payment.amount)}\n` +
|
|
// ... more details ...
|
|
`\n\n` +
|
|
`✅ Payment recorded successfully!\n` +
|
|
`Thank you for your trust! 🙏\n\n` +
|
|
`_Your Company Name_\n` + // Customize this
|
|
`_Website: yourwebsite.com_\n` + // Add your link
|
|
`_Support: +91-XXXXXXXXXX_`; // Add support number
|
|
}
|
|
|
|
// Example: Add regional language support
|
|
static generatePaymentReminderHindi(member, group, ...) {
|
|
return `⏰ *भुगतान अनुस्मारक*\n\n` +
|
|
`प्रिय ${member.full_name},\n\n` +
|
|
`आपकी मासिक किस्त ${daysLeft} दिनों में देय है।\n\n` +
|
|
// ... rest in Hindi
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 **Security Considerations**
|
|
|
|
### Rate Limiting:
|
|
|
|
```javascript
|
|
// Prevent spam
|
|
const rateLimit = require('express-rate-limit');
|
|
|
|
const shareLimit = rateLimit({
|
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
max: 10, // Max 10 shares per 15 minutes
|
|
message: 'Too many share requests'
|
|
});
|
|
|
|
router.post('/payment-receipt', shareLimit, auth, async (req, res) => {
|
|
// ...
|
|
});
|
|
```
|
|
|
|
### Validation:
|
|
|
|
```javascript
|
|
// Validate phone numbers
|
|
const validatePhone = (phone) => {
|
|
const cleaned = phone.replace(/\D/g, '');
|
|
return /^[0-9]{10}$/.test(cleaned);
|
|
};
|
|
|
|
// Validate ownership
|
|
if (payment.user_id !== req.user.id && req.user.role !== 'manager') {
|
|
return res.status(403).json({ message: 'Not authorized' });
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 💡 **Best Practices**
|
|
|
|
### 1. Always Log Notifications
|
|
```javascript
|
|
// Every WhatsApp action should create a notification record
|
|
await Notification.create({
|
|
type: 'payment_reminder',
|
|
user_id: memberId,
|
|
group_id: groupId,
|
|
channel: 'whatsapp',
|
|
message: message,
|
|
status: 'sent'
|
|
});
|
|
```
|
|
|
|
### 2. Handle Errors Gracefully
|
|
```javascript
|
|
try {
|
|
await WhatsAppUtil.shareReceipt(paymentId);
|
|
} catch (e) {
|
|
SnackbarUtil.showError('Could not open WhatsApp. Please try again.');
|
|
}
|
|
```
|
|
|
|
### 3. Provide Feedback
|
|
```javascript
|
|
// Show loading
|
|
SnackbarUtil.showLoading('Generating receipt...');
|
|
|
|
// Dismiss on complete
|
|
SnackbarUtil.dismiss();
|
|
SnackbarUtil.showSuccess('Opening WhatsApp...');
|
|
```
|
|
|
|
### 4. Respect User Preferences
|
|
```javascript
|
|
// Check if user wants WhatsApp notifications
|
|
if (user.preferences?.whatsapp_enabled) {
|
|
await sendWhatsAppReminder();
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 **Production Checklist**
|
|
|
|
Before going live:
|
|
|
|
- [ ] Test all WhatsApp share functions
|
|
- [ ] Verify scheduler runs at correct time
|
|
- [ ] Test reminder logic with various scenarios
|
|
- [ ] Check timezone handling (IST)
|
|
- [ ] Test with actual WhatsApp on mobile
|
|
- [ ] Verify phone number formatting
|
|
- [ ] Test bulk operations
|
|
- [ ] Monitor server logs
|
|
- [ ] Set up error alerts
|
|
- [ ] Test on multiple devices
|
|
- [ ] Verify database performance
|
|
- [ ] Add rate limiting
|
|
- [ ] Implement retry logic for failed sends
|
|
- [ ] Set up monitoring dashboard
|
|
|
|
---
|
|
|
|
## 📞 **Support & Troubleshooting**
|
|
|
|
### WhatsApp not opening?
|
|
- Check if WhatsApp is installed on device
|
|
- Verify phone number format (10 digits)
|
|
- Test URL in browser first
|
|
- Check console for errors
|
|
|
|
### Reminders not sending?
|
|
- Check server logs for cron execution
|
|
- Verify timezone settings
|
|
- Check database for notification records
|
|
- Test manual trigger: `ReminderService.triggerManualReminders()`
|
|
|
|
### Notifications not showing?
|
|
- Check API endpoint responses
|
|
- Verify NotificationService is initialized
|
|
- Check network connectivity
|
|
- Look for errors in Flutter console
|
|
|
|
---
|
|
|
|
## 🎉 **You're Ready!**
|
|
|
|
All WhatsApp integration and payment reminder features are now implemented!
|
|
|
|
**Next:** Test the features, customize messages, and deploy to production! 🚀
|
|
|