[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 typing import Any
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from base.forms import ModelForm
|
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.methods.methods import generate_choices
|
||||||
from horilla_automations.models import MODEL_CHOICES, MailAutomation
|
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):
|
class AutomationForm(ModelForm):
|
||||||
@@ -23,6 +28,19 @@ class AutomationForm(ModelForm):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*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:
|
if not self.data:
|
||||||
mail_to = []
|
mail_to = []
|
||||||
|
|
||||||
@@ -57,6 +75,18 @@ class AutomationForm(ModelForm):
|
|||||||
model = MailAutomation
|
model = MailAutomation
|
||||||
fields = "__all__"
|
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:
|
def save(self, commit: bool = ...) -> Any:
|
||||||
self.instance: MailAutomation = self.instance
|
self.instance: MailAutomation = self.instance
|
||||||
condition_querystring = self.cleaned_data["condition_querystring"]
|
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.methods import eval_validate
|
||||||
from base.models import HorillaMailTemplate
|
from base.models import HorillaMailTemplate
|
||||||
|
from employee.models import Employee
|
||||||
from horilla.models import HorillaModel
|
from horilla.models import HorillaModel
|
||||||
from horilla_views.cbv_methods import render_template
|
from horilla_views.cbv_methods import render_template
|
||||||
|
|
||||||
@@ -36,13 +37,20 @@ class MailAutomation(HorillaModel):
|
|||||||
mail_to = models.TextField(verbose_name="Mail to")
|
mail_to = models.TextField(verbose_name="Mail to")
|
||||||
mail_details = models.CharField(
|
mail_details = models.CharField(
|
||||||
max_length=250,
|
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)
|
mail_detail_choice = models.TextField(default="", editable=False)
|
||||||
trigger = models.CharField(max_length=10, choices=choices)
|
trigger = models.CharField(max_length=10, choices=choices)
|
||||||
# udpate the on_update logic to if and only if when
|
# udpate the on_update logic to if and only if when
|
||||||
# changes in the previous and current value
|
# changes in the previous and current value
|
||||||
mail_template = models.ForeignKey(HorillaMailTemplate, on_delete=models.CASCADE)
|
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(
|
template_attachments = models.ManyToManyField(
|
||||||
HorillaMailTemplate,
|
HorillaMailTemplate,
|
||||||
related_name="template_attachment",
|
related_name="template_attachment",
|
||||||
@@ -89,6 +97,12 @@ class MailAutomation(HorillaModel):
|
|||||||
"horilla_automations/mail_to.html", {"instance": self, "mappings": mappings}
|
"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):
|
def detailed_url(self):
|
||||||
return reverse("automation-detailed-view", kwargs={"pk": self.pk})
|
return reverse("automation-detailed-view", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
|
|||||||
@@ -40,12 +40,22 @@ def start_automation():
|
|||||||
"""
|
"""
|
||||||
Automation signals
|
Automation signals
|
||||||
"""
|
"""
|
||||||
|
from base.models import HorillaMailTemplate
|
||||||
from horilla_automations.methods.methods import get_model_class, split_query_string
|
from horilla_automations.methods.methods import get_model_class, split_query_string
|
||||||
from horilla_automations.models import MailAutomation
|
from horilla_automations.models import MailAutomation
|
||||||
|
|
||||||
@receiver(post_delete, sender=MailAutomation)
|
@receiver(post_delete, sender=MailAutomation)
|
||||||
@receiver(post_save, 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
|
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_bulk_record = getattr(_thread_locals, "previous_bulk_record", None)
|
||||||
previous_queryset = None
|
previous_queryset_copy = []
|
||||||
if previous_bulk_record:
|
if previous_bulk_record:
|
||||||
previous_queryset = previous_bulk_record["queryset"]
|
previous_queryset = previous_bulk_record.get("queryset", None)
|
||||||
previous_queryset_copy = previous_bulk_record["queryset_copy"]
|
previous_queryset_copy = previous_bulk_record.get("queryset_copy", [])
|
||||||
|
|
||||||
bulk_thread = threading.Thread(
|
bulk_thread = threading.Thread(
|
||||||
target=_bulk_update_thread_handler,
|
target=_bulk_update_thread_handler,
|
||||||
@@ -355,6 +365,19 @@ def send_mail(request, automation, instance):
|
|||||||
tos = list(filter(None, tos))
|
tos = list(filter(None, tos))
|
||||||
to = tos[:1]
|
to = tos[:1]
|
||||||
cc = 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()
|
email_backend = ConfiguredEmailBackend()
|
||||||
display_email_name = email_backend.dynamic_from_email_with_display_name
|
display_email_name = email_backend.dynamic_from_email_with_display_name
|
||||||
if request:
|
if request:
|
||||||
@@ -384,7 +407,9 @@ def send_mail(request, automation, instance):
|
|||||||
)
|
)
|
||||||
|
|
||||||
template_bdy = template.Template(mail_template.body)
|
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)
|
render_bdy = template_bdy.render(context)
|
||||||
|
|
||||||
title_template = template.Template(automation.title)
|
title_template = template.Template(automation.title)
|
||||||
|
|||||||
@@ -1,32 +1,39 @@
|
|||||||
<div id="formContainer">
|
<div id="formContainer">
|
||||||
{% include "generic/horilla_form.html" %}
|
{% include "generic/horilla_form.html" %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
$("#{{view_id}} form button").click(function (e) {
|
|
||||||
const form = document.getElementById('multipleConditionForm');
|
$(document).on('click', '.oh-accordion-header', function (event) {
|
||||||
const elements = form.elements;
|
$(this).closest('.oh-accordion').toggleClass('oh-accordion--show');
|
||||||
const queryString = Array.from(elements)
|
});
|
||||||
.filter(element => element.name && !element.disabled)
|
|
||||||
.map(element => encodeURIComponent(element.name) + '=' + encodeURIComponent(element.value))
|
$("#{{view_id}} form button").click(function (e) {
|
||||||
.join('&');
|
const form = document.getElementById('multipleConditionForm');
|
||||||
$("#{{view_id}} form [name=condition_querystring]").val(queryString);
|
const elements = form.elements;
|
||||||
html = $(".note-editable #multipleConditionForm").html()
|
const queryString = Array.from(elements)
|
||||||
$("#{{view_id}} form [name=condition_html]").val(html);
|
.filter(element => element.name && !element.disabled)
|
||||||
});
|
.map(element => encodeURIComponent(element.name) + '=' + encodeURIComponent(element.value))
|
||||||
$("#dynamic_field_condition").parent().removeClass("col-md-6");
|
.join('&');
|
||||||
// summernote
|
$("#{{view_id}} form [name=condition_querystring]").val(queryString);
|
||||||
$("#dynamic_field_condition textarea")
|
html = $(".note-editable #multipleConditionForm").html()
|
||||||
.summernote({
|
$("#{{view_id}} form [name=condition_html]").val(html);
|
||||||
height: 100,
|
});
|
||||||
toolbar: false,
|
|
||||||
})
|
$("#dynamic_field_condition").parent().removeClass("col-md-6");
|
||||||
.summernote("code", getHtml());
|
// summernote
|
||||||
{% if form.instance.pk %}
|
$("#dynamic_field_condition textarea")
|
||||||
$("#id_mail_to").val({{form.instance.mail_to|safe}}).change()
|
.summernote({
|
||||||
$("#dynamic_field_condition .note-editable").html($("<form id='multipleConditionForm'></form>"));
|
height: 100,
|
||||||
$("#dynamic_field_condition .note-editable #multipleConditionForm").html($(`{{form.instance.condition_html|safe}}`))
|
toolbar: false,
|
||||||
$(".note-editable select").parent().find("span.select2").remove()
|
})
|
||||||
$(".note-editable select").parent().find(".select2-hidden-accessible").removeClass("select2-hidden-accessible")
|
.summernote("code", getHtml());
|
||||||
$(".note-editable select").parent().find("select").select2();
|
{% if form.instance.pk %}
|
||||||
{% endif %}
|
$("#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>
|
</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"),
|
("Model", "model"),
|
||||||
("Mail Templates", "mail_template"),
|
("Mail Templates", "mail_template"),
|
||||||
("Mail To", "get_mail_to_display"),
|
("Mail To", "get_mail_to_display"),
|
||||||
|
("Mail Cc", "get_mail_cc_display"),
|
||||||
("Trigger", "trigger_display"),
|
("Trigger", "trigger_display"),
|
||||||
]
|
]
|
||||||
actions = [
|
actions = [
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from django import forms
|
|||||||
|
|
||||||
from horilla_widgets.widgets.horilla_multi_select_field import HorillaMultiSelectField
|
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"
|
forms.Select.option_template_name = "horilla_widgets/horilla_select_option.html"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@
|
|||||||
.select2{
|
.select2{
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
#slectContainer{{self.attrs.id}} .select2-container .select2-selection{
|
#selectContainer{{self.attrs.id}} .select2-container .select2-selection{
|
||||||
padding: 5px !important;
|
padding: 5px !important;
|
||||||
max-height: 70px !important;
|
max-height: 70px !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
</style>
|
</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>
|
<select name="{{field_name}}" id="{{self.attrs.id}}" {% if required %}required{% endif %} class="w-100 oh-select oh-select2" multiple>
|
||||||
{% for instance in queryset %}
|
{% for instance in queryset %}
|
||||||
<option value="{{instance.id}}">{{instance}}</option>
|
<option value="{{instance.id}}">{{instance}}</option>
|
||||||
|
|||||||
@@ -200,7 +200,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
{% if initial %}
|
{% 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 %}
|
{% endif %}
|
||||||
});
|
});
|
||||||
$("#{{section_id}} #choose-all-user").click(function (e) {
|
$("#{{section_id}} #choose-all-user").click(function (e) {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class HorillaMultiSelectWidget(forms.Widget):
|
|||||||
instance=None,
|
instance=None,
|
||||||
required=False,
|
required=False,
|
||||||
form=None,
|
form=None,
|
||||||
|
help_text=None,
|
||||||
**kwargs
|
**kwargs
|
||||||
) -> None:
|
) -> None:
|
||||||
self.filter_route_name = filter_route_name
|
self.filter_route_name = filter_route_name
|
||||||
@@ -45,6 +46,7 @@ class HorillaMultiSelectWidget(forms.Widget):
|
|||||||
self.filter_template_path = filter_template_path
|
self.filter_template_path = filter_template_path
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.form = form
|
self.form = form
|
||||||
|
self.help_text = help_text
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
template_name = "horilla_widgets/horilla_multiselect_widget.html"
|
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_template_path"] = self.filter_template_path
|
||||||
context["filter_route_name"] = self.filter_route_name
|
context["filter_route_name"] = self.filter_route_name
|
||||||
context["required"] = self.required
|
context["required"] = self.required
|
||||||
|
context["help_text"] = self.help_text
|
||||||
self.attrs["id"] = (
|
self.attrs["id"] = (
|
||||||
("id_" + name) if self.attrs.get("id") is None else self.attrs.get("id")
|
("id_" + name) if self.attrs.get("id") is None else self.attrs.get("id")
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user