1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
import datetime
from datetime import date as std_date
from typing import Optional, Dict
from django.contrib.auth import get_user_model
from django.db import models
from ctrack.organisations.models import Person
from ctrack.users.models import User
def _style_descriptor(days: int) -> str:
if days < 1:
return "red"
elif 0 < days < 5:
return "orange"
else:
return "black"
def _day_string(days: int) -> str:
if days < 1 or days > 1:
return "days"
else:
return "day"
class AuditableEventBase(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
created_date = models.DateTimeField()
modified_date = models.DateTimeField()
class Meta:
abstract = True
def save(self, *args, **kwargs):
"""Overriding so we can save the dates in here."""
if not self.pk:
self.created_date = datetime.datetime.now()
self.modified_date = datetime.datetime.now()
return super().save(*args, **kwargs)
class EngagementEventBase(AuditableEventBase):
type_descriptor = "Base Type"
short_description = models.CharField(
max_length=50,
help_text="Short description of the event. Use Comments field for full detail.",
)
participants = models.ManyToManyField(Person, null=True, blank=True)
document_link = models.URLField(
max_length=1000,
blank=True,
null=True,
help_text="URL only - do not try to drag a file here.",
)
response_date_requested = models.DateField(blank=True, null=True)
comments = models.TextField(max_length=1000, blank=True, null=True,
help_text="Use this to provide further detail about the event.")
class Meta:
abstract = True
class MeetingEventMixin(models.Model):
participants = models.ManyToManyField(Person, blank=False, null=False)
location = models.CharField(max_length=100, blank=False)
class Meta:
abstract = True
class SingleDateTimeEventMixin(models.Model):
datetime = models.DateTimeField()
class Meta:
abstract = True
# class SingleDateCAFEvent(EngagementEventBase):
# type = models.ForeignKey(
# EngagementType, default=event_type, on_delete=models.CASCADE
# )
# caf_related = models.BooleanField(default=True)
# date = models.DateField(blank=False, null=False)
class MeetingEvent(EngagementEventBase, MeetingEventMixin, SingleDateTimeEventMixin):
MEETING_TYPES = [
("Meeting", "Meeting")
]
type_descriptor = models.CharField(max_length=50, choices=MEETING_TYPES)
class EngagementType(models.Model):
"""
Examples here are Phone, Email, Letter, Site visit, Meeting, Audit, Inspection, etc.
Also official instruments such as designation letters, Information Notices, etc.
"""
descriptor = models.CharField(max_length=100, blank=False)
enforcement_instrument = models.BooleanField(default=False)
regulation_reference = models.CharField(max_length=100, blank=True, null=True)
comments = models.TextField(max_length=1000, blank=True, null=True)
single_date_type = models.BooleanField(default=False, blank=False)
def __str__(self):
return self.descriptor
class EngagementEvent(models.Model):
"""
Involves multiple people, such as a meeting, phone call, etc.
"""
def get_sentinel_user():
"""
We need this so that we can ensure models.SET() is applied with a callable
to handle when Users are deleted from the system, preventing the EngagementEvent
objects related to them being deleted also.
"""
return get_user_model().objects.get_or_create(username="DELETED USER")[0]
type = models.ForeignKey(EngagementType, on_delete=models.CASCADE)
short_description = models.CharField(
max_length=50, help_text="Short description of the event. Use Comments field for full detail."
)
participants = models.ManyToManyField(Person, blank=True)
user = models.ForeignKey(get_user_model(), on_delete=models.SET(get_sentinel_user))
date = models.DateTimeField()
end_date = models.DateTimeField(blank=True, null=True, help_text="Should be used for periodic events.")
document_link = models.URLField(max_length=1000, blank=True, null=True,
help_text="URL only - do not try to drag a file here.")
response_date_requested = models.DateField(blank=True, null=True)
response_received = models.DateField(blank=True, null=True)
related_caf = models.ForeignKey(
"caf.CAF", blank=True, on_delete=models.CASCADE, null=True,
help_text="If the event relates to a CAF, refer to it here."
)
comments = models.TextField(max_length=1000, blank=True, null=True,
help_text="Use this to provide further detail about the event.")
def days_to_response_due(self) -> Optional[Dict[int, str]]:
if self.response_date_requested:
today = std_date.today()
diff = self.response_date_requested - today
return dict(days=diff.days, descriptor=_style_descriptor(diff.days), day_str=_day_string(diff.days))
else:
return None
def __str__(self):
d = self.date.date()
iso_format_date = d.isoformat()
return f"{iso_format_date} | {self.type.descriptor} | {self.short_description}"
|