[UPDT] HORILLA AUTOMATIONS: Add also sent_to field in mail automation
This commit is contained in:
@@ -5,10 +5,15 @@ horilla_automations/forms.py
|
||||
from typing import Any
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from base.forms import ModelForm
|
||||
from employee.filters import EmployeeFilter
|
||||
from employee.models import Employee
|
||||
from horilla_automations.methods.methods import generate_choices
|
||||
from horilla_automations.models import MODEL_CHOICES, MailAutomation
|
||||
from horilla_widgets.widgets.horilla_multi_select_field import HorillaMultiSelectField
|
||||
from horilla_widgets.widgets.select_widgets import HorillaMultiSelectWidget
|
||||
|
||||
|
||||
class AutomationForm(ModelForm):
|
||||
@@ -23,6 +28,19 @@ class AutomationForm(ModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["also_sent_to"] = HorillaMultiSelectField(
|
||||
queryset=Employee.objects.all(),
|
||||
required=False,
|
||||
widget=HorillaMultiSelectWidget(
|
||||
filter_route_name="employee-widget-filter",
|
||||
filter_class=EmployeeFilter,
|
||||
filter_instance_contex_name="f",
|
||||
filter_template_path="employee_filters.html",
|
||||
instance=self.instance,
|
||||
),
|
||||
label="Also Sent to",
|
||||
help_text=_("The employees selected here will receive the email as Cc."),
|
||||
)
|
||||
if not self.data:
|
||||
mail_to = []
|
||||
|
||||
@@ -57,6 +75,18 @@ class AutomationForm(ModelForm):
|
||||
model = MailAutomation
|
||||
fields = "__all__"
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
if isinstance(self.fields["also_sent_to"], HorillaMultiSelectField):
|
||||
self.errors.pop("also_sent_to", None)
|
||||
|
||||
employee_data = self.fields["also_sent_to"].queryset.filter(
|
||||
id__in=self.data.getlist("also_sent_to")
|
||||
)
|
||||
cleaned_data["also_sent_to"] = employee_data
|
||||
|
||||
return cleaned_data
|
||||
|
||||
def save(self, commit: bool = ...) -> Any:
|
||||
self.instance: MailAutomation = self.instance
|
||||
condition_querystring = self.cleaned_data["condition_querystring"]
|
||||
|
||||
@@ -4,6 +4,7 @@ from django.utils.translation import gettext_lazy as _trans
|
||||
|
||||
from base.methods import eval_validate
|
||||
from base.models import HorillaMailTemplate
|
||||
from employee.models import Employee
|
||||
from horilla.models import HorillaModel
|
||||
from horilla_views.cbv_methods import render_template
|
||||
|
||||
@@ -36,13 +37,20 @@ class MailAutomation(HorillaModel):
|
||||
mail_to = models.TextField(verbose_name="Mail to")
|
||||
mail_details = models.CharField(
|
||||
max_length=250,
|
||||
help_text="Fill mail template details(reciever/instance, `self` will be the person who trigger the automation)",
|
||||
help_text=_trans(
|
||||
"Fill mail template details(reciever/instance, `self` will be the person who trigger the automation)"
|
||||
),
|
||||
)
|
||||
mail_detail_choice = models.TextField(default="", editable=False)
|
||||
trigger = models.CharField(max_length=10, choices=choices)
|
||||
# udpate the on_update logic to if and only if when
|
||||
# changes in the previous and current value
|
||||
mail_template = models.ForeignKey(HorillaMailTemplate, on_delete=models.CASCADE)
|
||||
also_sent_to = models.ManyToManyField(
|
||||
Employee,
|
||||
blank=True,
|
||||
verbose_name=_trans("Also Send to"),
|
||||
)
|
||||
template_attachments = models.ManyToManyField(
|
||||
HorillaMailTemplate,
|
||||
related_name="template_attachment",
|
||||
@@ -89,6 +97,12 @@ class MailAutomation(HorillaModel):
|
||||
"horilla_automations/mail_to.html", {"instance": self, "mappings": mappings}
|
||||
)
|
||||
|
||||
def get_mail_cc_display(self):
|
||||
employees = self.also_sent_to.all()
|
||||
return render_template(
|
||||
"horilla_automations/mail_cc.html", {"employees": employees}
|
||||
)
|
||||
|
||||
def detailed_url(self):
|
||||
return reverse("automation-detailed-view", kwargs={"pk": self.pk})
|
||||
|
||||
|
||||
@@ -40,12 +40,22 @@ def start_automation():
|
||||
"""
|
||||
Automation signals
|
||||
"""
|
||||
from base.models import HorillaMailTemplate
|
||||
from horilla_automations.methods.methods import get_model_class, split_query_string
|
||||
from horilla_automations.models import MailAutomation
|
||||
|
||||
@receiver(post_delete, sender=MailAutomation)
|
||||
@receiver(post_save, sender=MailAutomation)
|
||||
def automation_pre_create(sender, instance, **kwargs):
|
||||
def automation_signal(sender, instance, **kwargs):
|
||||
"""
|
||||
signal method to handle automation post save
|
||||
"""
|
||||
start_connection()
|
||||
track_previous_instance()
|
||||
|
||||
@receiver(post_delete, sender=HorillaMailTemplate)
|
||||
@receiver(post_save, sender=HorillaMailTemplate)
|
||||
def template_signal(sender, instance, **kwargs):
|
||||
"""
|
||||
signal method to handle automation post save
|
||||
"""
|
||||
@@ -81,10 +91,10 @@ def start_automation():
|
||||
)
|
||||
|
||||
previous_bulk_record = getattr(_thread_locals, "previous_bulk_record", None)
|
||||
previous_queryset = None
|
||||
previous_queryset_copy = []
|
||||
if previous_bulk_record:
|
||||
previous_queryset = previous_bulk_record["queryset"]
|
||||
previous_queryset_copy = previous_bulk_record["queryset_copy"]
|
||||
previous_queryset = previous_bulk_record.get("queryset", None)
|
||||
previous_queryset_copy = previous_bulk_record.get("queryset_copy", [])
|
||||
|
||||
bulk_thread = threading.Thread(
|
||||
target=_bulk_update_thread_handler,
|
||||
@@ -355,6 +365,19 @@ def send_mail(request, automation, instance):
|
||||
tos = list(filter(None, tos))
|
||||
to = tos[:1]
|
||||
cc = tos[1:]
|
||||
try:
|
||||
also_sent_to = automation.also_sent_to.select_related(
|
||||
"employee_work_info"
|
||||
).all()
|
||||
|
||||
if also_sent_to.exists():
|
||||
cc.extend(
|
||||
str(employee.get_mail())
|
||||
for employee in also_sent_to
|
||||
if employee.get_mail()
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
email_backend = ConfiguredEmailBackend()
|
||||
display_email_name = email_backend.dynamic_from_email_with_display_name
|
||||
if request:
|
||||
@@ -384,7 +407,9 @@ def send_mail(request, automation, instance):
|
||||
)
|
||||
|
||||
template_bdy = template.Template(mail_template.body)
|
||||
context = template.Context({"instance": mail_to_instance, "self": sender})
|
||||
context = template.Context(
|
||||
{"instance": mail_to_instance, "self": sender, "model_instance": instance}
|
||||
)
|
||||
render_bdy = template_bdy.render(context)
|
||||
|
||||
title_template = template.Template(automation.title)
|
||||
|
||||
@@ -1,32 +1,39 @@
|
||||
<div id="formContainer">
|
||||
{% include "generic/horilla_form.html" %}
|
||||
{% include "generic/horilla_form.html" %}
|
||||
|
||||
</div>
|
||||
<script>
|
||||
$("#{{view_id}} form button").click(function (e) {
|
||||
const form = document.getElementById('multipleConditionForm');
|
||||
const elements = form.elements;
|
||||
const queryString = Array.from(elements)
|
||||
.filter(element => element.name && !element.disabled)
|
||||
.map(element => encodeURIComponent(element.name) + '=' + encodeURIComponent(element.value))
|
||||
.join('&');
|
||||
$("#{{view_id}} form [name=condition_querystring]").val(queryString);
|
||||
html = $(".note-editable #multipleConditionForm").html()
|
||||
$("#{{view_id}} form [name=condition_html]").val(html);
|
||||
});
|
||||
$("#dynamic_field_condition").parent().removeClass("col-md-6");
|
||||
// summernote
|
||||
$("#dynamic_field_condition textarea")
|
||||
.summernote({
|
||||
height: 100,
|
||||
toolbar: false,
|
||||
})
|
||||
.summernote("code", getHtml());
|
||||
{% if form.instance.pk %}
|
||||
$("#id_mail_to").val({{form.instance.mail_to|safe}}).change()
|
||||
$("#dynamic_field_condition .note-editable").html($("<form id='multipleConditionForm'></form>"));
|
||||
$("#dynamic_field_condition .note-editable #multipleConditionForm").html($(`{{form.instance.condition_html|safe}}`))
|
||||
$(".note-editable select").parent().find("span.select2").remove()
|
||||
$(".note-editable select").parent().find(".select2-hidden-accessible").removeClass("select2-hidden-accessible")
|
||||
$(".note-editable select").parent().find("select").select2();
|
||||
{% endif %}
|
||||
|
||||
$(document).on('click', '.oh-accordion-header', function (event) {
|
||||
$(this).closest('.oh-accordion').toggleClass('oh-accordion--show');
|
||||
});
|
||||
|
||||
$("#{{view_id}} form button").click(function (e) {
|
||||
const form = document.getElementById('multipleConditionForm');
|
||||
const elements = form.elements;
|
||||
const queryString = Array.from(elements)
|
||||
.filter(element => element.name && !element.disabled)
|
||||
.map(element => encodeURIComponent(element.name) + '=' + encodeURIComponent(element.value))
|
||||
.join('&');
|
||||
$("#{{view_id}} form [name=condition_querystring]").val(queryString);
|
||||
html = $(".note-editable #multipleConditionForm").html()
|
||||
$("#{{view_id}} form [name=condition_html]").val(html);
|
||||
});
|
||||
|
||||
$("#dynamic_field_condition").parent().removeClass("col-md-6");
|
||||
// summernote
|
||||
$("#dynamic_field_condition textarea")
|
||||
.summernote({
|
||||
height: 100,
|
||||
toolbar: false,
|
||||
})
|
||||
.summernote("code", getHtml());
|
||||
{% if form.instance.pk %}
|
||||
$("#id_mail_to").val({{ form.instance.mail_to | safe }}).change()
|
||||
$("#dynamic_field_condition .note-editable").html($("<form id='multipleConditionForm'></form>"));
|
||||
$("#dynamic_field_condition .note-editable #multipleConditionForm").html($(`{{form.instance.condition_html|safe}}`))
|
||||
$(".note-editable select").parent().find("span.select2").remove()
|
||||
$(".note-editable select").parent().find(".select2-hidden-accessible").removeClass("select2-hidden-accessible")
|
||||
$(".note-editable select").parent().find("select").select2();
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{% load i18n %}
|
||||
{% if employees %}
|
||||
<ol>
|
||||
{% for employee in employees %}
|
||||
<li>{{employee}}</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% else %}
|
||||
{% trans "Not Added" %}
|
||||
{% endif %}
|
||||
@@ -162,6 +162,7 @@ class AutomationDetailedView(views.HorillaDetailedView):
|
||||
("Model", "model"),
|
||||
("Mail Templates", "mail_template"),
|
||||
("Mail To", "get_mail_to_display"),
|
||||
("Mail Cc", "get_mail_cc_display"),
|
||||
("Trigger", "trigger_display"),
|
||||
]
|
||||
actions = [
|
||||
|
||||
@@ -10,6 +10,7 @@ from django import forms
|
||||
|
||||
from horilla_widgets.widgets.horilla_multi_select_field import HorillaMultiSelectField
|
||||
|
||||
orginal_template_name = forms.Select.option_template_name
|
||||
forms.Select.option_template_name = "horilla_widgets/horilla_select_option.html"
|
||||
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
.select2{
|
||||
width: 100% !important;
|
||||
}
|
||||
#slectContainer{{self.attrs.id}} .select2-container .select2-selection{
|
||||
#selectContainer{{self.attrs.id}} .select2-container .select2-selection{
|
||||
padding: 5px !important;
|
||||
max-height: 70px !important;
|
||||
overflow: hidden;
|
||||
@@ -138,7 +138,7 @@
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
<div id="slectContainer{{self.attrs.id}}">
|
||||
<div id="selectContainer{{self.attrs.id}}">
|
||||
<select name="{{field_name}}" id="{{self.attrs.id}}" {% if required %}required{% endif %} class="w-100 oh-select oh-select2" multiple>
|
||||
{% for instance in queryset %}
|
||||
<option value="{{instance.id}}">{{instance}}</option>
|
||||
|
||||
@@ -200,7 +200,7 @@
|
||||
});
|
||||
});
|
||||
{% if initial %}
|
||||
$('#{{section_id}} #slectContainer{{self.attrs.id}}').find("[name={{field_name}}]").val({{initial|safe}}).change()
|
||||
$('#{{section_id}} #selectContainer{{self.attrs.id}}').find("[name={{field_name}}]").val({{initial|safe}}).change()
|
||||
{% endif %}
|
||||
});
|
||||
$("#{{section_id}} #choose-all-user").click(function (e) {
|
||||
|
||||
@@ -36,6 +36,7 @@ class HorillaMultiSelectWidget(forms.Widget):
|
||||
instance=None,
|
||||
required=False,
|
||||
form=None,
|
||||
help_text=None,
|
||||
**kwargs
|
||||
) -> None:
|
||||
self.filter_route_name = filter_route_name
|
||||
@@ -45,6 +46,7 @@ class HorillaMultiSelectWidget(forms.Widget):
|
||||
self.filter_template_path = filter_template_path
|
||||
self.instance = instance
|
||||
self.form = form
|
||||
self.help_text = help_text
|
||||
super().__init__()
|
||||
|
||||
template_name = "horilla_widgets/horilla_multiselect_widget.html"
|
||||
@@ -73,6 +75,7 @@ class HorillaMultiSelectWidget(forms.Widget):
|
||||
context["filter_template_path"] = self.filter_template_path
|
||||
context["filter_route_name"] = self.filter_route_name
|
||||
context["required"] = self.required
|
||||
context["help_text"] = self.help_text
|
||||
self.attrs["id"] = (
|
||||
("id_" + name) if self.attrs.get("id") is None else self.attrs.get("id")
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user