account, schduels, timezone profile and many imporant updates
This commit is contained in:
@@ -11,12 +11,66 @@ from django.db.models import Q, Count, Sum
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
import logging
|
||||
import secrets
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||
|
||||
from igny8_core.auth.models import Account
|
||||
from igny8_core.auth.models import Account, PasswordResetToken
|
||||
|
||||
COUNTRY_TIMEZONE_MAP = {
|
||||
'US': 'America/New_York',
|
||||
'GB': 'Europe/London',
|
||||
'CA': 'America/Toronto',
|
||||
'AU': 'Australia/Sydney',
|
||||
'IN': 'Asia/Kolkata',
|
||||
'PK': 'Asia/Karachi',
|
||||
'DE': 'Europe/Berlin',
|
||||
'FR': 'Europe/Paris',
|
||||
'ES': 'Europe/Madrid',
|
||||
'IT': 'Europe/Rome',
|
||||
'NL': 'Europe/Amsterdam',
|
||||
'SE': 'Europe/Stockholm',
|
||||
'NO': 'Europe/Oslo',
|
||||
'DK': 'Europe/Copenhagen',
|
||||
'FI': 'Europe/Helsinki',
|
||||
'BE': 'Europe/Brussels',
|
||||
'AT': 'Europe/Vienna',
|
||||
'CH': 'Europe/Zurich',
|
||||
'IE': 'Europe/Dublin',
|
||||
'NZ': 'Pacific/Auckland',
|
||||
'SG': 'Asia/Singapore',
|
||||
'AE': 'Asia/Dubai',
|
||||
'SA': 'Asia/Riyadh',
|
||||
'ZA': 'Africa/Johannesburg',
|
||||
'BR': 'America/Sao_Paulo',
|
||||
'MX': 'America/Mexico_City',
|
||||
'AR': 'America/Argentina/Buenos_Aires',
|
||||
'CL': 'America/Santiago',
|
||||
'CO': 'America/Bogota',
|
||||
'JP': 'Asia/Tokyo',
|
||||
'KR': 'Asia/Seoul',
|
||||
'CN': 'Asia/Shanghai',
|
||||
'TH': 'Asia/Bangkok',
|
||||
'MY': 'Asia/Kuala_Lumpur',
|
||||
'ID': 'Asia/Jakarta',
|
||||
'PH': 'Asia/Manila',
|
||||
'VN': 'Asia/Ho_Chi_Minh',
|
||||
'BD': 'Asia/Dhaka',
|
||||
'LK': 'Asia/Colombo',
|
||||
'EG': 'Africa/Cairo',
|
||||
'NG': 'Africa/Lagos',
|
||||
'KE': 'Africa/Nairobi',
|
||||
'GH': 'Africa/Accra',
|
||||
}
|
||||
|
||||
def _timezone_for_country(country_code: str | None) -> str:
|
||||
if not country_code:
|
||||
return 'UTC'
|
||||
return COUNTRY_TIMEZONE_MAP.get(country_code.upper(), 'UTC')
|
||||
from igny8_core.business.billing.models import CreditTransaction
|
||||
|
||||
User = get_user_model()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
@@ -43,6 +97,9 @@ class AccountSettingsViewSet(viewsets.ViewSet):
|
||||
'billing_country': account.billing_country or '',
|
||||
'tax_id': account.tax_id or '',
|
||||
'billing_email': account.billing_email or '',
|
||||
'account_timezone': account.account_timezone or 'UTC',
|
||||
'timezone_mode': account.timezone_mode or 'country',
|
||||
'timezone_offset': account.timezone_offset or '',
|
||||
'credits': account.credits,
|
||||
'created_at': account.created_at.isoformat(),
|
||||
'updated_at': account.updated_at.isoformat(),
|
||||
@@ -56,12 +113,19 @@ class AccountSettingsViewSet(viewsets.ViewSet):
|
||||
allowed_fields = [
|
||||
'name', 'billing_address_line1', 'billing_address_line2',
|
||||
'billing_city', 'billing_state', 'billing_postal_code',
|
||||
'billing_country', 'tax_id', 'billing_email'
|
||||
'billing_country', 'tax_id', 'billing_email',
|
||||
'account_timezone', 'timezone_mode', 'timezone_offset'
|
||||
]
|
||||
|
||||
for field in allowed_fields:
|
||||
if field in request.data:
|
||||
setattr(account, field, request.data[field])
|
||||
|
||||
# Derive timezone from country unless manual mode is selected
|
||||
if getattr(account, 'timezone_mode', 'country') != 'manual':
|
||||
country_code = account.billing_country
|
||||
account.account_timezone = _timezone_for_country(country_code)
|
||||
account.timezone_offset = ''
|
||||
|
||||
account.save()
|
||||
|
||||
@@ -79,6 +143,9 @@ class AccountSettingsViewSet(viewsets.ViewSet):
|
||||
'billing_country': account.billing_country,
|
||||
'tax_id': account.tax_id,
|
||||
'billing_email': account.billing_email,
|
||||
'account_timezone': account.account_timezone,
|
||||
'timezone_mode': account.timezone_mode,
|
||||
'timezone_offset': account.timezone_offset,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -142,13 +209,37 @@ class TeamManagementViewSet(viewsets.ViewSet):
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
# Create user (simplified - in production, send invitation email)
|
||||
# Generate username from email if not provided
|
||||
base_username = email.split('@')[0]
|
||||
username = base_username
|
||||
counter = 1
|
||||
while User.objects.filter(username=username).exists():
|
||||
username = f"{base_username}{counter}"
|
||||
counter += 1
|
||||
|
||||
# Create user and send invitation email
|
||||
user = User.objects.create_user(
|
||||
username=username,
|
||||
email=email,
|
||||
first_name=request.data.get('first_name', ''),
|
||||
last_name=request.data.get('last_name', ''),
|
||||
account=account
|
||||
)
|
||||
|
||||
# Create password reset token for invite
|
||||
token = secrets.token_urlsafe(32)
|
||||
expires_at = timezone.now() + timedelta(hours=24)
|
||||
PasswordResetToken.objects.create(
|
||||
user=user,
|
||||
token=token,
|
||||
expires_at=expires_at
|
||||
)
|
||||
|
||||
try:
|
||||
from igny8_core.business.billing.services.email_service import send_team_invite_email
|
||||
send_team_invite_email(user, request.user, account, token)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send team invite email: {e}")
|
||||
|
||||
return Response({
|
||||
'message': 'Team member invited successfully',
|
||||
|
||||
Reference in New Issue
Block a user