This guide covers common issues and solutions for PropManager.
- Authentication Issues
- Payment Problems
- Invoice Generation
- Background Tasks
- Email Delivery
- SMS Delivery
- Weather API
- E-Signature Issues
- Database Issues
- Performance Issues
Symptom: Tenant reports not receiving magic link email.
Solutions:
-
Check email address
- Verify the email is correct in the admin portal
- Check for typos (e.g.,
.coninstead of.com)
-
Check spam folder
- Magic links may be filtered as spam
- Have tenant add your sending domain to contacts
-
Verify email service
python manage.py shell >>> from django.core.mail import send_mail >>> send_mail('Test', 'Test message', 'noreply@example.com', ['test@example.com'])
If this fails, check email configuration.
-
Check email settings
# Verify environment variables echo $EMAIL_HOST echo $EMAIL_PORT echo $EMAIL_HOST_USER
Symptom: Admin receives "Permission denied" or redirect to login.
Solutions:
-
Verify user is staff
python manage.py shell >>> from django.contrib.auth import get_user_model >>> User = get_user_model() >>> user = User.objects.get(email='admin@example.com') >>> print(user.is_staff, user.is_active)
-
Reset password
python manage.py changepassword admin@example.com
-
Create new superuser
python manage.py createsuperuser
Symptom: Users are logged out frequently.
Solution: Check SESSION_COOKIE_AGE in settings:
# settings.py
SESSION_COOKIE_AGE = 86400 * 7 # 7 daysSymptom: Stripe payments return error or fail silently.
Check API Keys:
# Verify keys are set
echo $STRIPE_SECRET_KEY
echo $STRIPE_PUBLISHABLE_KEY
# Keys should start with:
# sk_live_ (live secret key)
# pk_live_ (live publishable key)
# sk_test_ (test secret key)
# pk_test_ (test publishable key)Check Webhook:
- Go to Stripe Dashboard → Developers → Webhooks
- Verify endpoint URL is correct:
https://yourdomain.com/webhooks/stripe/ - Check webhook secret matches
STRIPE_WEBHOOK_SECRET - Review recent webhook deliveries for errors
Common Errors:
| Error | Cause | Solution |
|---|---|---|
card_declined |
Card was declined | Ask tenant to try different card |
expired_card |
Card has expired | Update payment method |
incorrect_cvc |
Wrong security code | Re-enter card details |
processing_error |
Stripe processing issue | Retry later |
Symptom: PayPal buttons don't appear or payments fail.
Solutions:
-
Verify credentials
echo $PAYPAL_CLIENT_ID echo $PAYPAL_CLIENT_SECRET
-
Check sandbox mode
- Ensure
PAYPAL_SANDBOX=Truefor testing - Use sandbox credentials with sandbox mode
- Ensure
-
Test connectivity
import paypalrestsdk paypalrestsdk.configure({ "mode": "sandbox", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_SECRET" })
Symptom: Bank account linking fails.
Solutions:
-
Verify Plaid environment
sandbox- Testing only (use test credentials)development- Limited live banksproduction- Full access (requires approval)
-
Check Plaid credentials
echo $PLAID_CLIENT_ID echo $PLAID_SECRET echo $PLAID_ENV
-
Test Plaid connection
from plaid import Client client = Client(client_id='xxx', secret='xxx', environment='sandbox') # Test with sandbox institution
Symptom: Bitcoin payment shows as pending.
Solutions:
-
Check BTCPay Server status
- Verify BTCPay Server is running
- Check node sync status
-
Verify webhook configuration
- BTCPay webhook URL:
https://yourdomain.com/webhooks/btcpay/ - Webhook secret must match
- BTCPay webhook URL:
-
Check confirmation settings
- Default requires 1 confirmation
- Network congestion may delay confirmations
Symptom: Monthly invoices are not created automatically.
Check Django-Q2 Status:
# Check if cluster is running
python manage.py qinfo
# View scheduled tasks
python manage.py qmemoryVerify Task Schedule:
from django_q.models import Schedule
for s in Schedule.objects.all():
print(f"{s.name}: {s.schedule_type} - {s.next_run}")Run Manually:
python manage.py generate_monthly_invoicesCheck Lease Status:
from apps.leases.models import Lease
# Only active leases generate invoices
Lease.objects.filter(status='active').count()Symptom: Invoice total doesn't match expected rent.
Check billing configuration:
from apps.billing.models import PropertyBillingConfig
config = PropertyBillingConfig.objects.get(property_id=1)
print(f"Late fee: {config.late_fee_type} - {config.late_fee_amount}")Verify lease fees:
from apps.leases.models import LeaseFee
fees = LeaseFee.objects.filter(lease_id=1)
for fee in fees:
print(f"{fee.name}: ${fee.amount} ({fee.frequency})")Symptom: Overdue invoices don't have late fees.
Check grace period:
config = PropertyBillingConfig.objects.get(property_id=1)
print(f"Grace period: {config.grace_period_days} days")Run late fee task manually:
python manage.py apply_late_feesVerify invoice status:
from apps.billing.models import Invoice
from datetime import date
overdue = Invoice.objects.filter(
status='sent',
due_date__lt=date.today()
)
print(f"Overdue invoices: {overdue.count()}")Symptom: Background tasks are not executing.
Start the cluster:
python manage.py qclusterCheck for errors:
# View cluster logs
tail -f logs/qcluster.logVerify Redis connection:
redis-cli ping
# Should return PONGSymptom: Tasks are queued but not processing.
Check queue status:
python manage.py qinfoClear stuck tasks:
from django_q.models import OrmQ
# View pending tasks
OrmQ.objects.all()
# Clear all pending (use with caution)
OrmQ.objects.all().delete()Symptom: Tasks fail with errors.
View failed tasks:
from django_q.models import Failure
for f in Failure.objects.all()[:10]:
print(f"{f.name}: {f.result}")Retry failed task:
from django_q.models import Failure
failure = Failure.objects.last()
# Examine and fix the issue, then retry manuallySymptom: No emails are being delivered.
Check configuration:
from django.conf import settings
print(settings.EMAIL_BACKEND)
print(settings.EMAIL_HOST)
print(settings.EMAIL_PORT)Test email sending:
python manage.py shell
>>> from django.core.mail import send_mail
>>> send_mail(
... 'Test Subject',
... 'Test body',
... 'from@example.com',
... ['to@example.com'],
... fail_silently=False,
... )Common issues:
| Issue | Solution |
|---|---|
| Connection refused | Check EMAIL_HOST and EMAIL_PORT |
| Authentication failed | Verify EMAIL_HOST_USER and PASSWORD |
| SSL/TLS error | Check EMAIL_USE_TLS or EMAIL_USE_SSL |
| Timeout | Increase EMAIL_TIMEOUT setting |
Solutions:
-
Set up SPF record
v=spf1 include:_spf.youremailprovider.com ~all -
Set up DKIM
- Configure with your email provider
- Add DKIM record to DNS
-
Set up DMARC
v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com -
Use consistent From address
- Always send from the same domain
- Match From header with authenticated domain
Symptom: SMS messages are not delivered.
Verify credentials:
echo $TWILIO_ACCOUNT_SID
echo $TWILIO_AUTH_TOKEN
echo $TWILIO_PHONE_NUMBERTest SMS:
from twilio.rest import Client
client = Client(account_sid, auth_token)
message = client.messages.create(
body="Test message",
from_="+15551234567",
to="+15559876543"
)
print(message.sid)Common errors:
| Error | Cause | Solution |
|---|---|---|
| 21211 | Invalid 'To' number | Verify phone number format |
| 21608 | Unverified number | Verify number in Twilio console |
| 21614 | Not a mobile number | SMS only works with mobile numbers |
| 20003 | Auth failure | Check credentials |
Symptom: Some messages aren't delivered.
Solutions:
- Check Twilio logs in console
- Implement rate limiting in your code
- Use messaging service for higher throughput
- Upgrade Twilio account if needed
Symptom: Weather notifications not working.
Verify API key:
echo $OPENWEATHERMAP_API_KEYTest API:
curl "https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY"Check rate limits:
- Free tier: 60 calls/minute
- Monitor API usage in OpenWeatherMap dashboard
Symptom: Alerts triggered for wrong conditions.
Check alert thresholds:
from apps.communications.models import WeatherConfig
config = WeatherConfig.objects.first()
print(f"Heat threshold: {config.heat_threshold}")
print(f"Cold threshold: {config.cold_threshold}")Symptom: Tenant receives "Link Expired" message.
Solution: Links expire after 7 days. Resend the signing request:
- Go to lease detail in admin portal
- Click "Send for Signatures" again
- New links will be generated and sent
Symptom: Tenant completes signing but signature doesn't save.
Check:
- JavaScript errors - Check browser console
- Canvas support - Ensure browser supports HTML5 canvas
- Network errors - Check for failed API requests
Debug:
from apps.leases.models import LeaseSignature
sig = LeaseSignature.objects.last()
print(f"Signed: {sig.signed_at}")
print(f"Has image: {bool(sig.signature_image)}")Symptom: All parties signed but status isn't "executed".
Check signature status:
from apps.leases.models import Lease, LeaseSignature
lease = Lease.objects.get(pk=1)
sigs = LeaseSignature.objects.filter(lease=lease)
for sig in sigs:
print(f"{sig.signer_name}: {'Signed' if sig.signed_at else 'Pending'}")Manually update if needed:
lease.signature_status = 'executed'
lease.fully_executed_at = timezone.now()
lease.save()Symptom: migrate command fails.
Solutions:
-
Check migration status
python manage.py showmigrations
-
Fake problematic migration (if already applied manually)
python manage.py migrate app_name migration_name --fake
-
Reset migrations (development only)
python manage.py migrate app_name zero python manage.py migrate app_name
Symptom: "Could not connect to database" errors.
Check PostgreSQL:
# Check if PostgreSQL is running
sudo systemctl status postgresql
# Test connection
psql -h localhost -U propmanager -d propmanagerVerify settings:
from django.conf import settings
print(settings.DATABASES['default'])Symptom: Database queries are slow.
Identify slow queries:
from django.db import connection
print(connection.queries[-10:]) # Last 10 queriesAdd indexes:
class Meta:
indexes = [
models.Index(fields=['status', 'due_date']),
]Check:
- Database queries - Use Django Debug Toolbar
- N+1 queries - Add
select_related()andprefetch_related() - Caching - Implement Redis caching for frequent queries
Enable query logging:
LOGGING = {
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'level': 'DEBUG',
'handlers': ['console'],
},
},
}Solutions:
-
Paginate large querysets
from django.core.paginator import Paginator paginator = Paginator(Invoice.objects.all(), 100)
-
Use
iterator()for large datasetsfor invoice in Invoice.objects.all().iterator(): process(invoice)
-
Check for memory leaks in background tasks
Symptom: Caching or task queue fails.
Check Redis:
redis-cli ping
redis-cli info memoryTest from Django:
from django.core.cache import cache
cache.set('test', 'value', 60)
print(cache.get('test'))If you can't resolve an issue:
- Check logs -
logs/directory - Search issues - GitHub issues for similar problems
- Ask for help - Create a GitHub issue with:
- PropManager version
- Python/Django version
- Full error message
- Steps to reproduce