Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions temba/contacts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,11 +735,14 @@ def _get_campaign_events(self, campaigns) -> list:
if anchor is None: # contact has no value for this event's anchor field
continue

when = anchor + event.get_offset()
if event.delivery_hour >= 0 and event.unit in (CampaignEvent.UNIT_DAYS, CampaignEvent.UNIT_WEEKS):
when = when.astimezone(self.org.timezone).replace(
hour=event.delivery_hour, minute=0, second=0, microsecond=0
)
try:
when = anchor + event.get_offset()
if event.delivery_hour >= 0 and event.unit in (CampaignEvent.UNIT_DAYS, CampaignEvent.UNIT_WEEKS):
when = when.astimezone(self.org.timezone).replace(
hour=event.delivery_hour, minute=0, second=0, microsecond=0
)
except OverflowError: # anchor is so close to the min/max date that the event time isn't representable
continue

obj = {
"type": "campaign_event",
Expand Down
16 changes: 16 additions & 0 deletions temba/contacts/tests/test_contactcrudl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1350,11 +1350,27 @@ def test_timeline_inactive_and_missing_anchor(self):
inactive.is_active = False
inactive.save(update_fields=("is_active",))

# an event on a field whose value is so early that the event time isn't representable -> omitted
due = self.create_field("due", "Due On", value_type=ContactField.TYPE_DATETIME)
contact.fields[str(due.uuid)] = {"text": "0001-01-01", "datetime": "0001-01-01T00:00:00-06:36"}
contact.save(update_fields=("fields",))
CampaignEvent.create_message_event(
self.org,
self.admin,
campaign,
due,
-3,
unit="D",
translations={"eng": {"text": "Overflow"}},
base_language="eng",
)

response = self.requestView(timeline_url, self.admin)
future = response.json()["future"]

# only the single visible event survives
self.assertEqual(1, len(future))
self.assertEqual([], response.json()["past"])
self.assertEqual(1, response.json()["future_count"])
self.assertEqual(reverse("campaigns.campaign_read", args=[campaign.uuid]), future[0]["url"])
self.assertEqual("Visible", future[0]["message"])
Expand Down
Loading