CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-creme-crm

A comprehensive Customer Relationship Management software built on Django with extensive customization capabilities

Overview
Eval results
Files

activity-system.mddocs/

Activity & Calendar System

Comprehensive activity management with calendar integration, task scheduling, meeting coordination, and reminder systems for organizing business activities and time management.

Capabilities

Activity Management

Central activity entity for managing tasks, meetings, calls, and events.

class Activity(CremeEntity):
    """
    Activity entity for scheduling and managing business tasks and events.

    Attributes:
    - title: str, activity title/subject
    - description: TextField, detailed description
    - minutes: TextField, meeting minutes or notes
    - place: str, location or venue
    - duration: int, duration in minutes
    - start: DateTimeField, start date and time
    - end: DateTimeField, end date and time
    - is_all_day: bool, all-day event flag
    - status: ForeignKey, activity status
    - type: ForeignKey, activity type
    - sub_type: ForeignKey, activity sub-type
    - busy: bool, mark time as busy in calendar
    - floating_type: int, floating activity type

    Methods:
    - get_absolute_url(): Get activity detail URL
    - get_calendar_url(): Get calendar view URL
    - is_popup(): Check if activity is a popup reminder
    - get_duration_str(): Get formatted duration string
    - collides_with(other_activity): Check for scheduling conflicts
    - get_attendees(): Get list of participants
    """

def get_activity_model():
    """
    Get the active Activity model class from settings.

    Returns:
    type[Activity]: The configured activity model class

    Example:
    ActivityModel = get_activity_model()
    activity = ActivityModel.objects.create(
        title="Client Meeting",
        start=datetime.now(),
        duration=60
    )
    """

def activity_model_is_custom():
    """
    Check if the activity model has been customized.

    Returns:
    bool: True if using custom activity model
    """

Calendar Management

Calendar system for organizing and viewing activities.

class Calendar(CremeModel):
    """
    Calendar entity for organizing activities and events.

    Attributes:
    - name: str, calendar name
    - is_default: bool, default calendar flag
    - is_custom: bool, user-created calendar flag
    - is_public: bool, public visibility flag
    - user: ForeignKey, calendar owner
    - color: str, calendar display color

    Methods:
    - get_absolute_url(): Get calendar view URL
    - get_activities(start_date, end_date): Get activities in date range
    - is_visible_to(user): Check if user can view calendar
    - can_edit(user): Check if user can edit calendar
    - __str__(): Return calendar name
    """

Activity Types and Categorization

Classification system for different types of activities.

class ActivityType(CremeModel):
    """
    Main categorization for activities.

    Attributes:
    - name: str, type name
    - default_day_duration: int, default duration in minutes for day-long activities
    - default_hour_duration: int, default duration in minutes for timed activities
    - color: str, display color for this type
    - is_custom: bool, user-created type flag

    Methods:
    - __str__(): Return type name
    - get_default_duration(is_all_day): Get appropriate default duration

    Common Types:
    - Meeting, Phone Call, Task, Email, Visit, Conference
    """

class ActivitySubType(CremeModel):
    """
    Sub-categorization within activity types.

    Attributes:
    - name: str, sub-type name
    - type: ForeignKey, parent activity type
    - is_custom: bool, user-created sub-type flag

    Methods:
    - __str__(): Return sub-type name

    Examples:
    - Meeting: Internal, Client, Supplier, Board
    - Phone Call: Inbound, Outbound, Follow-up
    - Task: Administrative, Development, Research
    """

Activity Status

Status tracking for activity lifecycle management.

class Status(CremeModel):
    """
    Status options for activities throughout their lifecycle.

    Attributes:
    - name: str, status name
    - description: str, status description
    - color: str, display color
    - is_custom: bool, user-created status flag

    Methods:
    - __str__(): Return status name

    Common Statuses:
    - Planned, In Progress, Completed, Cancelled, Postponed
    """

Participation and Attendees

Managing activity participants and attendance.

class Relation(CremeModel):
    """
    Relationship between activities and participants.
    Uses the core relationship system to link activities with contacts/users.

    Activity-specific relation types:
    - 'activities-subject_participates': Contact participates in activity
    - 'activities-subject_is_invited': Contact is invited to activity
    - 'activities-subject_manages': Contact manages/organizes activity

    Methods:
    - get_participants(activity): Get list of activity participants
    - add_participant(activity, contact, relation_type): Add participant
    - remove_participant(activity, contact): Remove participant
    """

Usage Examples

Creating Activities

from creme.activities import get_activity_model
from creme.activities.models import ActivityType, ActivitySubType, Status
from datetime import datetime, timedelta

ActivityModel = get_activity_model()

# Create a basic meeting
meeting_type = ActivityType.objects.get(name="Meeting")
meeting_status = Status.objects.get(name="Planned")

activity = ActivityModel.objects.create(
    title="Weekly Team Meeting",
    description="Discuss project progress and next steps",
    start=datetime.now() + timedelta(days=1, hours=9),
    duration=60,  # 1 hour
    type=meeting_type,
    status=meeting_status,
    place="Conference Room A"
)

# Create all-day event
conference_activity = ActivityModel.objects.create(
    title="Industry Conference 2023",
    start=datetime.now() + timedelta(days=30),
    is_all_day=True,
    duration=1440,  # 24 hours
    type=meeting_type,
    status=meeting_status,
    place="Convention Center"
)

Calendar Operations

from creme.activities.models import Calendar

# Create personal calendar
personal_cal = Calendar.objects.create(
    name="Personal Schedule",
    user=request.user,
    is_default=True,
    is_public=False,
    color="#3498db"
)

# Create team calendar
team_cal = Calendar.objects.create(
    name="Team Activities",
    user=request.user,
    is_public=True,
    color="#e74c3c"
)

# Get activities for date range
from datetime import date
start_date = date.today()
end_date = start_date + timedelta(days=7)

week_activities = personal_cal.get_activities(start_date, end_date)

Adding Participants

from creme.creme_core.models import Relation, RelationType
from creme.persons import get_contact_model

ContactModel = get_contact_model()

# Get participants relation type
participates_rel = RelationType.objects.get(pk='activities-subject_participates')

# Add contacts as participants
participants = ContactModel.objects.filter(id__in=[1, 2, 3])
for contact in participants:
    Relation.objects.create(
        user=request.user,
        subject_entity=contact,
        object_entity=activity,
        type=participates_rel
    )

# Add meeting organizer
manages_rel = RelationType.objects.get(pk='activities-subject_manages')
organizer = ContactModel.objects.get(id=4)
Relation.objects.create(
    user=request.user,
    subject_entity=organizer,
    object_entity=activity,
    type=manages_rel
)

Scheduling and Conflict Detection

# Check for scheduling conflicts
def check_conflicts(activity, user):
    """Check if activity conflicts with existing schedule."""
    overlapping = ActivityModel.objects.filter(
        user=user,
        start__lt=activity.end,
        end__gt=activity.start,
        busy=True
    ).exclude(id=activity.id if activity.id else None)

    return overlapping

# Find available time slots
def find_available_slots(start_date, end_date, duration_minutes, user):
    """Find free time slots for scheduling."""
    busy_times = ActivityModel.objects.filter(
        user=user,
        start__date__range=[start_date, end_date],
        busy=True
    ).order_by('start')

    available_slots = []
    current_time = datetime.combine(start_date, datetime.min.time().replace(hour=9))
    end_time = datetime.combine(end_date, datetime.min.time().replace(hour=17))

    for activity in busy_times:
        if current_time + timedelta(minutes=duration_minutes) <= activity.start:
            available_slots.append({
                'start': current_time,
                'end': activity.start,
                'duration': (activity.start - current_time).total_seconds() / 60
            })
        current_time = max(current_time, activity.end)

    return available_slots

Recurring Activities

from dateutil.rrule import rrule, WEEKLY, DAILY

def create_recurring_activity(base_activity, recurrence_rule, count=None, until=None):
    """Create recurring activities based on a template."""
    activities = []

    # Generate dates based on recurrence rule
    if count:
        dates = list(rrule(recurrence_rule, dtstart=base_activity.start, count=count))
    elif until:
        dates = list(rrule(recurrence_rule, dtstart=base_activity.start, until=until))
    else:
        # Default to 10 occurrences
        dates = list(rrule(recurrence_rule, dtstart=base_activity.start, count=10))

    for occurrence_date in dates[1:]:  # Skip first occurrence (original)
        duration = timedelta(minutes=base_activity.duration)
        recurring_activity = ActivityModel.objects.create(
            title=base_activity.title,
            description=base_activity.description,
            start=occurrence_date,
            end=occurrence_date + duration,
            duration=base_activity.duration,
            type=base_activity.type,
            sub_type=base_activity.sub_type,
            status=base_activity.status,
            place=base_activity.place,
            busy=base_activity.busy
        )
        activities.append(recurring_activity)

    return activities

# Create weekly team meeting
weekly_meetings = create_recurring_activity(
    base_activity=team_meeting,
    recurrence_rule=WEEKLY,
    count=12  # 12 weeks
)

Activity Reporting

from django.db.models import Count, Sum, Q
from datetime import datetime, timedelta

# Activity statistics for user
def get_activity_stats(user, start_date, end_date):
    """Get activity statistics for date range."""
    activities = ActivityModel.objects.filter(
        user=user,
        start__date__range=[start_date, end_date]
    )

    stats = {
        'total_activities': activities.count(),
        'completed_activities': activities.filter(status__name='Completed').count(),
        'total_duration': activities.aggregate(Sum('duration'))['duration__sum'] or 0,
        'by_type': activities.values('type__name').annotate(count=Count('id')),
        'by_status': activities.values('status__name').annotate(count=Count('id')),
    }

    return stats

# Overdue activities
overdue_activities = ActivityModel.objects.filter(
    end__lt=datetime.now(),
    status__name__in=['Planned', 'In Progress']
)

# Today's schedule
today_activities = ActivityModel.objects.filter(
    start__date=date.today()
).order_by('start')

Integration with Other Modules

# Link activity to opportunity
from creme.opportunities import get_opportunity_model
from creme.creme_core.models import RelationType

OpportunityModel = get_opportunity_model()
opportunity = OpportunityModel.objects.get(id=1)

# Create follow-up call activity
followup_rel = RelationType.objects.get(pk='activities-subject_linked_2_activity')
followup_call = ActivityModel.objects.create(
    title="Follow up on proposal",
    start=datetime.now() + timedelta(days=3),
    duration=30,
    type=ActivityType.objects.get(name="Phone Call"),
    status=Status.objects.get(name="Planned")
)

Relation.objects.create(
    user=request.user,
    subject_entity=followup_call,
    object_entity=opportunity,
    type=followup_rel
)

# Link activity to invoice (payment reminder)
from creme.billing import get_invoice_model

InvoiceModel = get_invoice_model()
invoice = InvoiceModel.objects.get(id=1)

payment_reminder = ActivityModel.objects.create(
    title=f"Payment reminder for {invoice.name}",
    start=invoice.expiration_date + timedelta(days=7),
    duration=15,
    type=ActivityType.objects.get(name="Phone Call"),
    status=Status.objects.get(name="Planned")
)

Relation.objects.create(
    user=request.user,
    subject_entity=payment_reminder,
    object_entity=invoice,
    type=followup_rel
)

Calendar Views and Export

# Generate calendar data for frontend
def get_calendar_events(user, start_date, end_date):
    """Get calendar events in format suitable for calendar widgets."""
    activities = ActivityModel.objects.filter(
        user=user,
        start__range=[start_date, end_date]
    ).select_related('type', 'status')

    events = []
    for activity in activities:
        events.append({
            'id': activity.id,
            'title': activity.title,
            'start': activity.start.isoformat(),
            'end': activity.end.isoformat() if activity.end else None,
            'allDay': activity.is_all_day,
            'color': activity.type.color if activity.type else '#3498db',
            'url': activity.get_absolute_url()
        })

    return events

# Export to iCal format
def export_calendar_ical(activities):
    """Export activities to iCal format."""
    from icalendar import Calendar, Event

    cal = Calendar()
    cal.add('prodid', '-//Creme CRM//Calendar//EN')
    cal.add('version', '2.0')

    for activity in activities:
        event = Event()
        event.add('summary', activity.title)
        event.add('dtstart', activity.start)
        if activity.end:
            event.add('dtend', activity.end)
        if activity.description:
            event.add('description', activity.description)
        if activity.place:
            event.add('location', activity.place)

        cal.add_component(event)

    return cal.to_ical()

The activity system provides comprehensive scheduling and time management capabilities that integrate seamlessly with all other CRM modules for complete business activity coordination.

Install with Tessl CLI

npx tessl i tessl/pypi-creme-crm

docs

activity-system.md

api-integration.md

billing-system.md

configuration-system.md

console-interface.md

contact-management.md

core-framework.md

django-settings.md

document-management.md

email-system.md

event-system.md

import-export-system.md

index.md

management-commands.md

plugin-development.md

product-catalog.md

reporting-system.md

sales-management.md

system-configuration.md

template-system.md

ticket-system.md

user-management.md

tile.json