or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

activity-system.mdapi-integration.mdbilling-system.mdconfiguration-system.mdconsole-interface.mdcontact-management.mdcore-framework.mddjango-settings.mddocument-management.mdemail-system.mdevent-system.mdimport-export-system.mdindex.mdmanagement-commands.mdplugin-development.mdproduct-catalog.mdreporting-system.mdsales-management.mdsystem-configuration.mdtemplate-system.mdticket-system.mduser-management.md

activity-system.mddocs/

0

# Activity & Calendar System

1

2

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

3

4

## Capabilities

5

6

### Activity Management

7

8

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

9

10

```python { .api }

11

class Activity(CremeEntity):

12

"""

13

Activity entity for scheduling and managing business tasks and events.

14

15

Attributes:

16

- title: str, activity title/subject

17

- description: TextField, detailed description

18

- minutes: TextField, meeting minutes or notes

19

- place: str, location or venue

20

- duration: int, duration in minutes

21

- start: DateTimeField, start date and time

22

- end: DateTimeField, end date and time

23

- is_all_day: bool, all-day event flag

24

- status: ForeignKey, activity status

25

- type: ForeignKey, activity type

26

- sub_type: ForeignKey, activity sub-type

27

- busy: bool, mark time as busy in calendar

28

- floating_type: int, floating activity type

29

30

Methods:

31

- get_absolute_url(): Get activity detail URL

32

- get_calendar_url(): Get calendar view URL

33

- is_popup(): Check if activity is a popup reminder

34

- get_duration_str(): Get formatted duration string

35

- collides_with(other_activity): Check for scheduling conflicts

36

- get_attendees(): Get list of participants

37

"""

38

39

def get_activity_model():

40

"""

41

Get the active Activity model class from settings.

42

43

Returns:

44

type[Activity]: The configured activity model class

45

46

Example:

47

ActivityModel = get_activity_model()

48

activity = ActivityModel.objects.create(

49

title="Client Meeting",

50

start=datetime.now(),

51

duration=60

52

)

53

"""

54

55

def activity_model_is_custom():

56

"""

57

Check if the activity model has been customized.

58

59

Returns:

60

bool: True if using custom activity model

61

"""

62

```

63

64

### Calendar Management

65

66

Calendar system for organizing and viewing activities.

67

68

```python { .api }

69

class Calendar(CremeModel):

70

"""

71

Calendar entity for organizing activities and events.

72

73

Attributes:

74

- name: str, calendar name

75

- is_default: bool, default calendar flag

76

- is_custom: bool, user-created calendar flag

77

- is_public: bool, public visibility flag

78

- user: ForeignKey, calendar owner

79

- color: str, calendar display color

80

81

Methods:

82

- get_absolute_url(): Get calendar view URL

83

- get_activities(start_date, end_date): Get activities in date range

84

- is_visible_to(user): Check if user can view calendar

85

- can_edit(user): Check if user can edit calendar

86

- __str__(): Return calendar name

87

"""

88

```

89

90

### Activity Types and Categorization

91

92

Classification system for different types of activities.

93

94

```python { .api }

95

class ActivityType(CremeModel):

96

"""

97

Main categorization for activities.

98

99

Attributes:

100

- name: str, type name

101

- default_day_duration: int, default duration in minutes for day-long activities

102

- default_hour_duration: int, default duration in minutes for timed activities

103

- color: str, display color for this type

104

- is_custom: bool, user-created type flag

105

106

Methods:

107

- __str__(): Return type name

108

- get_default_duration(is_all_day): Get appropriate default duration

109

110

Common Types:

111

- Meeting, Phone Call, Task, Email, Visit, Conference

112

"""

113

114

class ActivitySubType(CremeModel):

115

"""

116

Sub-categorization within activity types.

117

118

Attributes:

119

- name: str, sub-type name

120

- type: ForeignKey, parent activity type

121

- is_custom: bool, user-created sub-type flag

122

123

Methods:

124

- __str__(): Return sub-type name

125

126

Examples:

127

- Meeting: Internal, Client, Supplier, Board

128

- Phone Call: Inbound, Outbound, Follow-up

129

- Task: Administrative, Development, Research

130

"""

131

```

132

133

### Activity Status

134

135

Status tracking for activity lifecycle management.

136

137

```python { .api }

138

class Status(CremeModel):

139

"""

140

Status options for activities throughout their lifecycle.

141

142

Attributes:

143

- name: str, status name

144

- description: str, status description

145

- color: str, display color

146

- is_custom: bool, user-created status flag

147

148

Methods:

149

- __str__(): Return status name

150

151

Common Statuses:

152

- Planned, In Progress, Completed, Cancelled, Postponed

153

"""

154

```

155

156

### Participation and Attendees

157

158

Managing activity participants and attendance.

159

160

```python { .api }

161

class Relation(CremeModel):

162

"""

163

Relationship between activities and participants.

164

Uses the core relationship system to link activities with contacts/users.

165

166

Activity-specific relation types:

167

- 'activities-subject_participates': Contact participates in activity

168

- 'activities-subject_is_invited': Contact is invited to activity

169

- 'activities-subject_manages': Contact manages/organizes activity

170

171

Methods:

172

- get_participants(activity): Get list of activity participants

173

- add_participant(activity, contact, relation_type): Add participant

174

- remove_participant(activity, contact): Remove participant

175

"""

176

```

177

178

## Usage Examples

179

180

### Creating Activities

181

182

```python

183

from creme.activities import get_activity_model

184

from creme.activities.models import ActivityType, ActivitySubType, Status

185

from datetime import datetime, timedelta

186

187

ActivityModel = get_activity_model()

188

189

# Create a basic meeting

190

meeting_type = ActivityType.objects.get(name="Meeting")

191

meeting_status = Status.objects.get(name="Planned")

192

193

activity = ActivityModel.objects.create(

194

title="Weekly Team Meeting",

195

description="Discuss project progress and next steps",

196

start=datetime.now() + timedelta(days=1, hours=9),

197

duration=60, # 1 hour

198

type=meeting_type,

199

status=meeting_status,

200

place="Conference Room A"

201

)

202

203

# Create all-day event

204

conference_activity = ActivityModel.objects.create(

205

title="Industry Conference 2023",

206

start=datetime.now() + timedelta(days=30),

207

is_all_day=True,

208

duration=1440, # 24 hours

209

type=meeting_type,

210

status=meeting_status,

211

place="Convention Center"

212

)

213

```

214

215

### Calendar Operations

216

217

```python

218

from creme.activities.models import Calendar

219

220

# Create personal calendar

221

personal_cal = Calendar.objects.create(

222

name="Personal Schedule",

223

user=request.user,

224

is_default=True,

225

is_public=False,

226

color="#3498db"

227

)

228

229

# Create team calendar

230

team_cal = Calendar.objects.create(

231

name="Team Activities",

232

user=request.user,

233

is_public=True,

234

color="#e74c3c"

235

)

236

237

# Get activities for date range

238

from datetime import date

239

start_date = date.today()

240

end_date = start_date + timedelta(days=7)

241

242

week_activities = personal_cal.get_activities(start_date, end_date)

243

```

244

245

### Adding Participants

246

247

```python

248

from creme.creme_core.models import Relation, RelationType

249

from creme.persons import get_contact_model

250

251

ContactModel = get_contact_model()

252

253

# Get participants relation type

254

participates_rel = RelationType.objects.get(pk='activities-subject_participates')

255

256

# Add contacts as participants

257

participants = ContactModel.objects.filter(id__in=[1, 2, 3])

258

for contact in participants:

259

Relation.objects.create(

260

user=request.user,

261

subject_entity=contact,

262

object_entity=activity,

263

type=participates_rel

264

)

265

266

# Add meeting organizer

267

manages_rel = RelationType.objects.get(pk='activities-subject_manages')

268

organizer = ContactModel.objects.get(id=4)

269

Relation.objects.create(

270

user=request.user,

271

subject_entity=organizer,

272

object_entity=activity,

273

type=manages_rel

274

)

275

```

276

277

### Scheduling and Conflict Detection

278

279

```python

280

# Check for scheduling conflicts

281

def check_conflicts(activity, user):

282

"""Check if activity conflicts with existing schedule."""

283

overlapping = ActivityModel.objects.filter(

284

user=user,

285

start__lt=activity.end,

286

end__gt=activity.start,

287

busy=True

288

).exclude(id=activity.id if activity.id else None)

289

290

return overlapping

291

292

# Find available time slots

293

def find_available_slots(start_date, end_date, duration_minutes, user):

294

"""Find free time slots for scheduling."""

295

busy_times = ActivityModel.objects.filter(

296

user=user,

297

start__date__range=[start_date, end_date],

298

busy=True

299

).order_by('start')

300

301

available_slots = []

302

current_time = datetime.combine(start_date, datetime.min.time().replace(hour=9))

303

end_time = datetime.combine(end_date, datetime.min.time().replace(hour=17))

304

305

for activity in busy_times:

306

if current_time + timedelta(minutes=duration_minutes) <= activity.start:

307

available_slots.append({

308

'start': current_time,

309

'end': activity.start,

310

'duration': (activity.start - current_time).total_seconds() / 60

311

})

312

current_time = max(current_time, activity.end)

313

314

return available_slots

315

```

316

317

### Recurring Activities

318

319

```python

320

from dateutil.rrule import rrule, WEEKLY, DAILY

321

322

def create_recurring_activity(base_activity, recurrence_rule, count=None, until=None):

323

"""Create recurring activities based on a template."""

324

activities = []

325

326

# Generate dates based on recurrence rule

327

if count:

328

dates = list(rrule(recurrence_rule, dtstart=base_activity.start, count=count))

329

elif until:

330

dates = list(rrule(recurrence_rule, dtstart=base_activity.start, until=until))

331

else:

332

# Default to 10 occurrences

333

dates = list(rrule(recurrence_rule, dtstart=base_activity.start, count=10))

334

335

for occurrence_date in dates[1:]: # Skip first occurrence (original)

336

duration = timedelta(minutes=base_activity.duration)

337

recurring_activity = ActivityModel.objects.create(

338

title=base_activity.title,

339

description=base_activity.description,

340

start=occurrence_date,

341

end=occurrence_date + duration,

342

duration=base_activity.duration,

343

type=base_activity.type,

344

sub_type=base_activity.sub_type,

345

status=base_activity.status,

346

place=base_activity.place,

347

busy=base_activity.busy

348

)

349

activities.append(recurring_activity)

350

351

return activities

352

353

# Create weekly team meeting

354

weekly_meetings = create_recurring_activity(

355

base_activity=team_meeting,

356

recurrence_rule=WEEKLY,

357

count=12 # 12 weeks

358

)

359

```

360

361

### Activity Reporting

362

363

```python

364

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

365

from datetime import datetime, timedelta

366

367

# Activity statistics for user

368

def get_activity_stats(user, start_date, end_date):

369

"""Get activity statistics for date range."""

370

activities = ActivityModel.objects.filter(

371

user=user,

372

start__date__range=[start_date, end_date]

373

)

374

375

stats = {

376

'total_activities': activities.count(),

377

'completed_activities': activities.filter(status__name='Completed').count(),

378

'total_duration': activities.aggregate(Sum('duration'))['duration__sum'] or 0,

379

'by_type': activities.values('type__name').annotate(count=Count('id')),

380

'by_status': activities.values('status__name').annotate(count=Count('id')),

381

}

382

383

return stats

384

385

# Overdue activities

386

overdue_activities = ActivityModel.objects.filter(

387

end__lt=datetime.now(),

388

status__name__in=['Planned', 'In Progress']

389

)

390

391

# Today's schedule

392

today_activities = ActivityModel.objects.filter(

393

start__date=date.today()

394

).order_by('start')

395

```

396

397

### Integration with Other Modules

398

399

```python

400

# Link activity to opportunity

401

from creme.opportunities import get_opportunity_model

402

from creme.creme_core.models import RelationType

403

404

OpportunityModel = get_opportunity_model()

405

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

406

407

# Create follow-up call activity

408

followup_rel = RelationType.objects.get(pk='activities-subject_linked_2_activity')

409

followup_call = ActivityModel.objects.create(

410

title="Follow up on proposal",

411

start=datetime.now() + timedelta(days=3),

412

duration=30,

413

type=ActivityType.objects.get(name="Phone Call"),

414

status=Status.objects.get(name="Planned")

415

)

416

417

Relation.objects.create(

418

user=request.user,

419

subject_entity=followup_call,

420

object_entity=opportunity,

421

type=followup_rel

422

)

423

424

# Link activity to invoice (payment reminder)

425

from creme.billing import get_invoice_model

426

427

InvoiceModel = get_invoice_model()

428

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

429

430

payment_reminder = ActivityModel.objects.create(

431

title=f"Payment reminder for {invoice.name}",

432

start=invoice.expiration_date + timedelta(days=7),

433

duration=15,

434

type=ActivityType.objects.get(name="Phone Call"),

435

status=Status.objects.get(name="Planned")

436

)

437

438

Relation.objects.create(

439

user=request.user,

440

subject_entity=payment_reminder,

441

object_entity=invoice,

442

type=followup_rel

443

)

444

```

445

446

### Calendar Views and Export

447

448

```python

449

# Generate calendar data for frontend

450

def get_calendar_events(user, start_date, end_date):

451

"""Get calendar events in format suitable for calendar widgets."""

452

activities = ActivityModel.objects.filter(

453

user=user,

454

start__range=[start_date, end_date]

455

).select_related('type', 'status')

456

457

events = []

458

for activity in activities:

459

events.append({

460

'id': activity.id,

461

'title': activity.title,

462

'start': activity.start.isoformat(),

463

'end': activity.end.isoformat() if activity.end else None,

464

'allDay': activity.is_all_day,

465

'color': activity.type.color if activity.type else '#3498db',

466

'url': activity.get_absolute_url()

467

})

468

469

return events

470

471

# Export to iCal format

472

def export_calendar_ical(activities):

473

"""Export activities to iCal format."""

474

from icalendar import Calendar, Event

475

476

cal = Calendar()

477

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

478

cal.add('version', '2.0')

479

480

for activity in activities:

481

event = Event()

482

event.add('summary', activity.title)

483

event.add('dtstart', activity.start)

484

if activity.end:

485

event.add('dtend', activity.end)

486

if activity.description:

487

event.add('description', activity.description)

488

if activity.place:

489

event.add('location', activity.place)

490

491

cal.add_component(event)

492

493

return cal.to_ical()

494

```

495

496

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