feat: Add comprehensive plugin documentation and advanced template system
Added complete plugin documentation with visual mockups and expanded template
variable system with CONTEXT, DATE helpers, and default values.
Backend Changes:
- Extended template_parser.py to support all new template types
- Added PROMPT with default values: {{PROMPT:var|desc|default}}
- Added CONTEXT variables: {{CONTEXT:business_name}}, {{CONTEXT:owner_email}}
- Added DATE helpers: {{DATE:today}}, {{DATE:+7d}}, {{DATE:monday}}
- Implemented date expression evaluation for relative dates
- Updated compile_template to handle all template types
- Added context parameter for business data auto-fill
Frontend Changes:
- Created comprehensive HelpPluginDocs.tsx with Stripe-style API docs
- Added visual mockup of plugin configuration form
- Documented all template types with examples and benefits
- Added Command Reference section with allowed/blocked Python commands
- Documented all HTTP methods (GET, POST, PUT, PATCH, DELETE)
- Added URL whitelisting requirements and approval process
- Created Platform Staff management page with edit modal
- Added can_approve_plugins and can_whitelist_urls permissions
Platform Staff Features:
- List all platform_manager and platform_support users
- Edit user details with role-based permissions
- Superusers can edit anyone
- Platform managers can only edit platform_support users
- Permission cascade: users can only grant permissions they have
- Real-time updates via React Query cache invalidation
Documentation Highlights:
- 4 template types: PROMPT, CONTEXT, DATE, and automatic validation
- Visual form mockup showing exactly what users see
- All allowed control flow (if/elif/else, for, while, try/except, etc.)
- All allowed built-in functions (len, range, min, max, etc.)
- All blocked operations (import, exec, eval, class/function defs)
- Complete HTTP API reference with examples
- URL whitelisting process: contact pluginaccess@smoothschedule.com
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
472
smoothschedule/SCRIPTING_EXAMPLES.md
Normal file
472
smoothschedule/SCRIPTING_EXAMPLES.md
Normal file
@@ -0,0 +1,472 @@
|
||||
# Custom Script Examples - Quick Reference
|
||||
|
||||
Copy and paste these examples to get started quickly!
|
||||
|
||||
## 1. Send Weekly Summary Email
|
||||
|
||||
```python
|
||||
# Get appointments from last 7 days
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
end = datetime.now().strftime('%Y-%m-%d')
|
||||
start = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
|
||||
|
||||
appointments = api.get_appointments(
|
||||
start_date=start,
|
||||
end_date=end,
|
||||
limit=500
|
||||
)
|
||||
|
||||
# Count by status
|
||||
scheduled = sum(1 for a in appointments if a['status'] == 'SCHEDULED')
|
||||
completed = sum(1 for a in appointments if a['status'] == 'COMPLETED')
|
||||
canceled = sum(1 for a in appointments if a['status'] == 'CANCELED')
|
||||
|
||||
# Build report
|
||||
report = f"""
|
||||
Weekly Summary ({start} to {end})
|
||||
|
||||
Total Appointments: {len(appointments)}
|
||||
- Scheduled: {scheduled}
|
||||
- Completed: {completed}
|
||||
- Canceled: {canceled}
|
||||
|
||||
Completion Rate: {(completed / len(appointments) * 100):.1f}%
|
||||
"""
|
||||
|
||||
# Send it
|
||||
api.send_email(
|
||||
to='manager@yourbusiness.com',
|
||||
subject=f'Weekly Summary - {start}',
|
||||
body=report
|
||||
)
|
||||
|
||||
result = {'total': len(appointments), 'completed': completed}
|
||||
```
|
||||
|
||||
**Schedule:** `0 9 * * 1` (Every Monday at 9 AM)
|
||||
|
||||
---
|
||||
|
||||
## 2. Re-engage Inactive Customers
|
||||
|
||||
```python
|
||||
# Get appointments from last 90 days
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
cutoff = (datetime.now() - timedelta(days=90)).strftime('%Y-%m-%d')
|
||||
recent_appointments = api.get_appointments(start_date=cutoff, limit=500)
|
||||
|
||||
# Get all customers
|
||||
all_customers = api.get_customers(has_email=True, limit=200)
|
||||
|
||||
# Find who booked recently (simplified - in production use customer IDs)
|
||||
recent_customer_emails = {apt['title'] for apt in recent_appointments}
|
||||
|
||||
# Find inactive customers
|
||||
inactive = []
|
||||
for customer in all_customers:
|
||||
if customer['email'] not in recent_customer_emails:
|
||||
inactive.append(customer)
|
||||
|
||||
# Send re-engagement emails (limit to 30 per run)
|
||||
sent = 0
|
||||
for customer in inactive[:30]:
|
||||
message = f"""Hi {customer['name']},
|
||||
|
||||
We noticed it's been a while since your last visit!
|
||||
|
||||
We'd love to see you again. Book this week and get 20% off with code: COMEBACK20
|
||||
|
||||
Hope to see you soon!
|
||||
"""
|
||||
|
||||
success = api.send_email(
|
||||
to=customer['email'],
|
||||
subject='We Miss You! 20% Off Inside',
|
||||
body=message
|
||||
)
|
||||
|
||||
if success:
|
||||
sent += 1
|
||||
|
||||
api.log(f'Sent {sent} re-engagement emails')
|
||||
result = {'inactive_found': len(inactive), 'emails_sent': sent}
|
||||
```
|
||||
|
||||
**Schedule:** `0 10 * * 3` (Every Wednesday at 10 AM)
|
||||
|
||||
---
|
||||
|
||||
## 3. Alert on Low Bookings
|
||||
|
||||
```python
|
||||
# Get appointments for next 7 days
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
next_week = (datetime.now() + timedelta(days=7)).strftime('%Y-%m-%d')
|
||||
|
||||
upcoming = api.get_appointments(
|
||||
start_date=today,
|
||||
end_date=next_week,
|
||||
status='SCHEDULED',
|
||||
limit=200
|
||||
)
|
||||
|
||||
# If less than 10 appointments, send alert
|
||||
if len(upcoming) < 10:
|
||||
alert = f"""
|
||||
⚠️ LOW BOOKING ALERT
|
||||
|
||||
Only {len(upcoming)} appointments scheduled for the next 7 days.
|
||||
|
||||
Recommendation: Run a promotion or send reminders to past customers.
|
||||
|
||||
This is below your normal booking rate.
|
||||
"""
|
||||
|
||||
api.send_email(
|
||||
to='owner@yourbusiness.com',
|
||||
subject='⚠️ Low Booking Alert',
|
||||
body=alert
|
||||
)
|
||||
|
||||
result = {'alert_sent': True, 'upcoming_count': len(upcoming)}
|
||||
else:
|
||||
result = {'alert_sent': False, 'upcoming_count': len(upcoming)}
|
||||
```
|
||||
|
||||
**Schedule:** `0 8 * * *` (Every day at 8 AM)
|
||||
|
||||
---
|
||||
|
||||
## 4. Birthday Campaign
|
||||
|
||||
```python
|
||||
# Get all customers
|
||||
customers = api.get_customers(has_email=True, limit=500)
|
||||
|
||||
# Today's date (simplified birthday check)
|
||||
from datetime import datetime
|
||||
today = datetime.now()
|
||||
|
||||
# Send birthday wishes (simplified - in production check actual birthdays)
|
||||
birthday_customers = []
|
||||
|
||||
for customer in customers:
|
||||
# In real usage, you'd have birthday field
|
||||
# This is a placeholder
|
||||
is_birthday = False # Replace with actual birthday check
|
||||
|
||||
if is_birthday:
|
||||
birthday_customers.append(customer)
|
||||
|
||||
message = f"""Happy Birthday, {customer['name']}! 🎉
|
||||
|
||||
Celebrate with us! Get 25% off any service this week with code: BIRTHDAY25
|
||||
|
||||
We hope you have an amazing day!
|
||||
"""
|
||||
|
||||
api.send_email(
|
||||
to=customer['email'],
|
||||
subject='🎉 Happy Birthday! Special Gift Inside',
|
||||
body=message
|
||||
)
|
||||
|
||||
api.log(f'Sent {len(birthday_customers)} birthday emails')
|
||||
result = {'birthday_emails_sent': len(birthday_customers)}
|
||||
```
|
||||
|
||||
**Schedule:** `0 9 * * *` (Every day at 9 AM)
|
||||
|
||||
---
|
||||
|
||||
## 5. Appointment Reminder (Day Before)
|
||||
|
||||
```python
|
||||
# Get appointments for tomorrow
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
tomorrow_start = (datetime.now() + timedelta(days=1)).replace(hour=0, minute=0).strftime('%Y-%m-%d')
|
||||
tomorrow_end = (datetime.now() + timedelta(days=1)).replace(hour=23, minute=59).strftime('%Y-%m-%d')
|
||||
|
||||
tomorrow_appointments = api.get_appointments(
|
||||
start_date=tomorrow_start,
|
||||
end_date=tomorrow_end,
|
||||
status='SCHEDULED',
|
||||
limit=100
|
||||
)
|
||||
|
||||
# Send reminders
|
||||
sent = 0
|
||||
for apt in tomorrow_appointments:
|
||||
# Extract time
|
||||
time_str = apt['start_time'].split('T')[1][:5] # Get HH:MM
|
||||
|
||||
reminder = f"""Appointment Reminder
|
||||
|
||||
You have an appointment tomorrow at {time_str}.
|
||||
|
||||
Title: {apt['title']}
|
||||
Time: {time_str}
|
||||
|
||||
See you then!
|
||||
|
||||
Reply CANCEL to cancel or RESCHEDULE to change the time.
|
||||
"""
|
||||
|
||||
# In production, you'd get customer email from appointment
|
||||
# This is simplified
|
||||
customer_email = 'customer@example.com'
|
||||
|
||||
success = api.send_email(
|
||||
to=customer_email,
|
||||
subject='Reminder: Appointment Tomorrow',
|
||||
body=reminder
|
||||
)
|
||||
|
||||
if success:
|
||||
sent += 1
|
||||
|
||||
result = {'reminders_sent': sent, 'appointments_tomorrow': len(tomorrow_appointments)}
|
||||
```
|
||||
|
||||
**Schedule:** `0 18 * * *` (Every day at 6 PM)
|
||||
|
||||
---
|
||||
|
||||
## 6. Monthly Performance Report
|
||||
|
||||
```python
|
||||
# Get last month's data
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Calculate last month
|
||||
today = datetime.now()
|
||||
first_of_this_month = today.replace(day=1)
|
||||
last_month_end = (first_of_this_month - timedelta(days=1)).strftime('%Y-%m-%d')
|
||||
last_month_start = (first_of_this_month - timedelta(days=31)).replace(day=1).strftime('%Y-%m-%d')
|
||||
|
||||
appointments = api.get_appointments(
|
||||
start_date=last_month_start,
|
||||
end_date=last_month_end,
|
||||
limit=1000
|
||||
)
|
||||
|
||||
# Calculate metrics
|
||||
total = len(appointments)
|
||||
completed = sum(1 for a in appointments if a['status'] == 'COMPLETED')
|
||||
canceled = sum(1 for a in appointments if a['status'] == 'CANCELED')
|
||||
no_show_rate = (canceled / total * 100) if total > 0 else 0
|
||||
|
||||
# Group by week
|
||||
weekly_counts = {}
|
||||
for apt in appointments:
|
||||
# Get week number
|
||||
date_str = apt['start_time'].split('T')[0]
|
||||
weekly_counts[date_str[:7]] = weekly_counts.get(date_str[:7], 0) + 1
|
||||
|
||||
# Build report
|
||||
report = f"""
|
||||
Monthly Performance Report
|
||||
Period: {last_month_start} to {last_month_end}
|
||||
|
||||
OVERVIEW
|
||||
--------
|
||||
Total Appointments: {total}
|
||||
Completed: {completed}
|
||||
Canceled: {canceled}
|
||||
No-Show Rate: {no_show_rate:.1f}%
|
||||
|
||||
WEEKLY BREAKDOWN
|
||||
----------------
|
||||
"""
|
||||
|
||||
for week in sorted(weekly_counts.keys()):
|
||||
report += f"{week}: {weekly_counts[week]} appointments\n"
|
||||
|
||||
report += f"\n{'📈' if completed > 50 else '📉'} "
|
||||
report += "Great month!" if completed > 50 else "Consider increasing marketing"
|
||||
|
||||
# Send report
|
||||
api.send_email(
|
||||
to='owner@yourbusiness.com',
|
||||
subject=f'Monthly Report - {last_month_start}',
|
||||
body=report
|
||||
)
|
||||
|
||||
result = {
|
||||
'total': total,
|
||||
'completed': completed,
|
||||
'no_show_rate': round(no_show_rate, 2)
|
||||
}
|
||||
```
|
||||
|
||||
**Schedule:** `0 9 1 * *` (First day of month at 9 AM)
|
||||
|
||||
---
|
||||
|
||||
## 7. VIP Customer Recognition
|
||||
|
||||
```python
|
||||
# Get appointments from last 6 months
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
six_months_ago = (datetime.now() - timedelta(days=180)).strftime('%Y-%m-%d')
|
||||
appointments = api.get_appointments(start_date=six_months_ago, limit=1000)
|
||||
|
||||
# Count visits per customer (simplified)
|
||||
customer_visits = {}
|
||||
for apt in appointments:
|
||||
# In production, extract actual customer ID
|
||||
customer_id = apt.get('customer_id', 'unknown')
|
||||
customer_visits[customer_id] = customer_visits.get(customer_id, 0) + 1
|
||||
|
||||
# Find VIP customers (5+ visits)
|
||||
vip_count = sum(1 for visits in customer_visits.values() if visits >= 5)
|
||||
|
||||
# Get customers
|
||||
customers = api.get_customers(has_email=True, limit=100)
|
||||
|
||||
# Send VIP recognition
|
||||
sent = 0
|
||||
for customer in customers:
|
||||
visits = customer_visits.get(customer['id'], 0)
|
||||
|
||||
if visits >= 5:
|
||||
message = f"""Hi {customer['name']},
|
||||
|
||||
You're officially a VIP! 🌟
|
||||
|
||||
You've visited us {visits} times in the last 6 months, and we truly appreciate your loyalty.
|
||||
|
||||
As a thank you, here's an exclusive 30% off code: VIP30
|
||||
|
||||
Valid for your next 3 visits!
|
||||
|
||||
Thank you for being amazing!
|
||||
"""
|
||||
|
||||
success = api.send_email(
|
||||
to=customer['email'],
|
||||
subject='🌟 You are a VIP Customer!',
|
||||
body=message
|
||||
)
|
||||
|
||||
if success:
|
||||
sent += 1
|
||||
|
||||
result = {'vip_customers': vip_count, 'emails_sent': sent}
|
||||
```
|
||||
|
||||
**Schedule:** `0 10 1 * *` (First of month at 10 AM)
|
||||
|
||||
---
|
||||
|
||||
## 8. Capacity Optimization Alert
|
||||
|
||||
```python
|
||||
# Get next 30 days of appointments
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
thirty_days = (datetime.now() + timedelta(days=30)).strftime('%Y-%m-%d')
|
||||
|
||||
upcoming = api.get_appointments(
|
||||
start_date=today,
|
||||
end_date=thirty_days,
|
||||
status='SCHEDULED',
|
||||
limit=500
|
||||
)
|
||||
|
||||
# Group by date
|
||||
daily_bookings = {}
|
||||
for apt in upcoming:
|
||||
date = apt['start_time'].split('T')[0]
|
||||
daily_bookings[date] = daily_bookings.get(date, 0) + 1
|
||||
|
||||
# Find issues
|
||||
overbooked = []
|
||||
underbooked = []
|
||||
|
||||
for date, count in daily_bookings.items():
|
||||
if count > 15: # More than 15 per day = overbooked
|
||||
overbooked.append(f"{date}: {count} appointments")
|
||||
elif count < 3: # Less than 3 = underbooked
|
||||
underbooked.append(f"{date}: {count} appointments")
|
||||
|
||||
# Send alert if needed
|
||||
if overbooked or underbooked:
|
||||
alert = "Capacity Alert\n\n"
|
||||
|
||||
if overbooked:
|
||||
alert += "⚠️ OVERBOOKED DAYS:\n"
|
||||
alert += "\n".join(overbooked)
|
||||
alert += "\n\nConsider adding staff or limiting bookings.\n\n"
|
||||
|
||||
if underbooked:
|
||||
alert += "📉 UNDERBOOKED DAYS:\n"
|
||||
alert += "\n".join(underbooked)
|
||||
alert += "\n\nConsider running promotions.\n"
|
||||
|
||||
api.send_email(
|
||||
to='manager@yourbusiness.com',
|
||||
subject='Capacity Alert - Action Needed',
|
||||
body=alert
|
||||
)
|
||||
|
||||
result = {
|
||||
'overbooked_days': len(overbooked),
|
||||
'underbooked_days': len(underbooked)
|
||||
}
|
||||
```
|
||||
|
||||
**Schedule:** `0 7 * * 1` (Every Monday at 7 AM)
|
||||
|
||||
---
|
||||
|
||||
## Tips for Success
|
||||
|
||||
1. **Start Simple** - Copy one example and modify it
|
||||
2. **Test First** - Use "Execute Now" to test before scheduling
|
||||
3. **Check Logs** - Review execution logs for errors
|
||||
4. **Add Logging** - Use `api.log()` to debug
|
||||
5. **Limit Batches** - Don't send too many emails at once
|
||||
6. **Schedule Wisely** - Consider your business hours
|
||||
|
||||
## Common Modifications
|
||||
|
||||
### Change Email Content
|
||||
```python
|
||||
# Replace the message string with your own text
|
||||
message = f"""Your custom message here
|
||||
|
||||
Use {customer['name']} for personalization
|
||||
"""
|
||||
```
|
||||
|
||||
### Adjust Date Ranges
|
||||
```python
|
||||
# Change the number of days
|
||||
days_back = 30 # Instead of 7, 14, 90, etc.
|
||||
start = (datetime.now() - timedelta(days=days_back)).strftime('%Y-%m-%d')
|
||||
```
|
||||
|
||||
### Filter by Status
|
||||
```python
|
||||
# Only get specific statuses
|
||||
appointments = api.get_appointments(
|
||||
status='COMPLETED', # or 'SCHEDULED', 'CANCELED'
|
||||
limit=100
|
||||
)
|
||||
```
|
||||
|
||||
### Limit Results
|
||||
```python
|
||||
# Process fewer customers
|
||||
customers = api.get_customers(limit=20) # Instead of 100
|
||||
```
|
||||
|
||||
Happy automating! 🚀
|
||||
Reference in New Issue
Block a user