- Implement tests for closing tickets via menu and status picker, ensuring correct API interactions and error handling. - Create tests for calendar feed provider, verifying throttling behavior and success responses. - Add tests for deal board provider, covering reading and moving deals, including edge cases for card movement and filters. - Enhance macro tests to validate action parsing and application to tickets, including error handling. - Introduce session cache tests to ensure proper cleanup on sign-out and validate session-scoped providers. - Extend web form model tests to cover lead rotation functionality, ensuring correct serialization and defaults.
111 lines
3.8 KiB
Python
111 lines
3.8 KiB
Python
"""Background work for web forms.
|
|
|
|
A Celery worker does not run Django middleware, so `set_rls_context` has to be
|
|
called explicitly before any ORM query. Without it every query below runs with
|
|
an empty `app.current_org` and returns zero rows, which reads as "no submission
|
|
found" rather than as a bug.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from celery import shared_task
|
|
from django.template.loader import render_to_string
|
|
|
|
from common.links import frontend_url
|
|
from common.tasks import set_rls_context
|
|
from leads.tasks import send_email
|
|
from webforms.models import WebFormSubmission
|
|
from webforms.service import active_assignee
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@shared_task
|
|
def send_webform_submission_email(submission_id, org_id):
|
|
"""Tell the form's recipients that a lead or ticket came in.
|
|
|
|
The only mail a submission sends. Recipients are the form's active
|
|
`notify_profiles` plus the record's assignee: the lead's own active
|
|
assignees on a lead form, the form's active `assign_to` on a ticket form.
|
|
One message to the union, so an assignee who is also a notify recipient
|
|
receives one email rather than two.
|
|
|
|
Rejected submissions notify nobody. Telling an org about every bot that
|
|
hits their form is how they learn to ignore the notification, and then to
|
|
miss the real one.
|
|
|
|
`send_email` is called directly rather than through `.delay()`. This is
|
|
already inside a task, so enqueuing a second one buys nothing and would
|
|
only add a hop where the message can be lost.
|
|
"""
|
|
set_rls_context(org_id)
|
|
|
|
submission = (
|
|
WebFormSubmission.objects.filter(id=submission_id, org_id=org_id)
|
|
.select_related("form", "lead", "case", "form__assign_to")
|
|
.first()
|
|
)
|
|
if submission is None:
|
|
logger.info(
|
|
"Web form submission %s is gone or belongs to another org; "
|
|
"nothing to notify.",
|
|
submission_id,
|
|
)
|
|
return
|
|
|
|
if submission.status not in WebFormSubmission.ACCEPTED_STATUSES:
|
|
return
|
|
|
|
form = submission.form
|
|
# Active members only: a deactivated one has left, and this mail carries
|
|
# the prospect's details.
|
|
profiles = set(
|
|
form.notify_profiles.filter(is_active=True).select_related("user").all()
|
|
)
|
|
if submission.case_id:
|
|
assignee = active_assignee(form)
|
|
if assignee is not None:
|
|
profiles.add(assignee)
|
|
elif submission.lead_id:
|
|
# Whoever the lead actually belongs to, not the form's `assign_to`. A
|
|
# rotation form picks a different member each time, and a repeat
|
|
# submission merges into a lead somebody else may already own.
|
|
profiles.update(
|
|
submission.lead.assigned_to.filter(
|
|
org_id=org_id, is_active=True
|
|
).select_related("user")
|
|
)
|
|
|
|
recipients = sorted(
|
|
{
|
|
profile.user.email
|
|
for profile in profiles
|
|
if getattr(profile, "user", None) and profile.user.email
|
|
}
|
|
)
|
|
if not recipients:
|
|
logger.info("Web form %s has no notification recipients.", form.id)
|
|
return
|
|
|
|
if submission.case_id:
|
|
record_url = frontend_url(f"/tickets/{submission.case_id}")
|
|
subject = f"New ticket: {form.name}"
|
|
else:
|
|
record_url = frontend_url(f"/leads/{submission.lead_id}")
|
|
subject = f"New submission: {form.name}"
|
|
html_content = render_to_string(
|
|
"webforms/submission_email.html",
|
|
{
|
|
"form": form,
|
|
"submission": submission,
|
|
"lead": submission.lead,
|
|
"case": submission.case,
|
|
"record_url": record_url,
|
|
"is_duplicate": (submission.status == WebFormSubmission.ACCEPTED_DUPLICATE),
|
|
},
|
|
)
|
|
send_email(
|
|
subject=subject,
|
|
html_content=html_content,
|
|
recipients=recipients,
|
|
)
|