""" horilla_automations/methods/methods.py """ import operator from django.core.exceptions import FieldDoesNotExist from django.db import models as django_models from django.http import QueryDict from base.templatetags.horillafilters import app_installed from employee.models import Employee from horilla.models import HorillaModel recruitment_installed = False if app_installed("recruitment"): from recruitment.models import Candidate recruitment_installed = True def get_related_models(model: HorillaModel) -> list: related_models = [] for field in model._meta.get_fields(): if field.one_to_many or field.one_to_one or field.many_to_many: related_model = field.related_model related_models.append(related_model) return related_models from horilla_automations.methods.recursive_relation import ( get_forward_relation_paths_separated, ) def generate_choices(model_path): """ Generate mail to choice """ module_name, class_name = model_path.rsplit(".", 1) module = __import__(module_name, fromlist=[class_name]) model_class: Employee = getattr(module, class_name) # Get relations to Employee employee_fk_paths, employee_m2m_paths = get_forward_relation_paths_separated( model_class, Employee ) # Get relations to Candidate candidate_fk_paths, candidate_m2m_paths = get_forward_relation_paths_separated( model_class, Candidate ) all_fields = ( employee_fk_paths + employee_m2m_paths + candidate_fk_paths + candidate_m2m_paths ) all_mail_to_field = [] mail_details_choice = [] for field_tuple in all_fields: if not getattr(field_tuple[1], "exclude_from_automation", False): all_mail_to_field.append( ( f"{field_tuple[0]}__get_email", f"({field_tuple[1].model.__name__}) {field_tuple[1].verbose_name.capitalize().replace(' id','')}'s mail ", ) ) if not field_tuple[1].many_to_many: mail_details_choice += [ ( f"{field_tuple[0]}__pk", f"{field_tuple[1].verbose_name.capitalize().replace(' id','')} (Template context)", ), ] # Adding reporting manager if the related model is Employee if field_tuple[1].related_model == Employee: # reporting manager mail to all_mail_to_field.append( ( f"{field_tuple[0]}__employee_work_info__reporting_manager_id__get_email", f"{field_tuple[1].verbose_name.capitalize().replace(' id','')} / Reporting Manager's mail ", ) ) # reporting manager template context mail_details_choice.append( ( f"{field_tuple[0]}__employee_work_info__reporting_manager_id__pk", f"{field_tuple[1].verbose_name.capitalize().replace(' id','')} / Reporting Manager (Template context) ", ) ) if model_class == Employee: # reporting manager mail to all_mail_to_field.append( ( f"employee_work_info__reporting_manager_id__get_email", f"Reporting Manager's mail ", ) ) mail_details_choice.append(("pk", "Employee")) if model_class == Candidate: mail_details_choice.append(("pk", "Candidate")) if model_path == "employee.models.Employee": all_mail_to_field.append(("get_email", "Employee's mail")) elif model_path == "recruitment.models.Candidate": all_mail_to_field.append(("get_email", "Candidate's mail")) to_fields = [] # mail_details_choice = [] # for field in list(model_class._meta.fields) + list(model_class._meta.many_to_many): # if not getattr(field, "exclude_from_automation", False): # related_model = field.related_model # models = [Employee] # if recruitment_installed: # models.append(Candidate) # if related_model in models: # email_field = ( # f"{field.name}__get_email", # f"{field.verbose_name.capitalize().replace(' id','')} mail field ", # ) # mail_detail = None # if not isinstance(field, django_models.ManyToManyField): # mail_detail = ( # f"{field.name}__pk", # field.verbose_name.capitalize().replace(" id", "") # + "(Template context)", # ) # if field.related_model == Employee: # to_fields.append( # ( # f"{field.name}__employee_work_info__reporting_manager_id__get_email", # f"{field.verbose_name.capitalize().replace(' id','')}'s reporting manager", # ) # ) # if not isinstance(field, django_models.ManyToManyField): # mail_details_choice.append( # ( # f"{field.name}__employee_work_info__reporting_manager_id__pk", # f"{field.verbose_name.capitalize().replace(' id','')}'s reporting manager (Template context)", # ) # ) # to_fields.append(email_field) # if mail_detail: # mail_details_choice.append(mail_detail) text_area_fields = get_textfield_paths(model_class) mail_details_choice = mail_details_choice + text_area_fields # models = [Employee] # if recruitment_installed: # models.append(Candidate) # if model_class in models: # to_fields.append( # ( # "get_email", # f"{model_class.__name__}'s mail ({model_class.__name__})", # ) # ) # mail_to_related_fields = getattr(model_class, "mail_to_related_fields", []) # to_fields = to_fields + mail_to_related_fields # mail_details_choice.append(("pk", model_class.__name__)) to_fields = list(set(to_fields)) return all_mail_to_field, mail_details_choice, model_class def get_model_class(model_path): """ method to return the model class from string 'app.models.Model' """ module_name, class_name = model_path.rsplit(".", 1) module = __import__(module_name, fromlist=[class_name]) model_class: Employee = getattr(module, class_name) return model_class operator_map = { "==": operator.eq, "!=": operator.ne, "and": lambda x, y: x and y, "or": lambda x, y: x or y, } def querydict(query_string): query_dict = QueryDict(query_string) return query_dict def split_query_string(query_string): """ Split the query string based on the "&logic=" substring """ query_parts = query_string.split("&logic=") result = [] for i, part in enumerate(query_parts): if i != 0: result.append(querydict("&logic=" + part)) else: result.append(querydict(part)) return result def evaluate_condition(value1, operator_str, value2): op_func = operator_map.get(operator_str) if op_func is None: raise ValueError(f"Invalid operator: {operator_str}") return op_func(value1, value2) def get_related_field_model(model: Employee, field_path): parts = field_path.split("__") for part in parts: # Handle the special case for 'pk' if part == "pk": field = model._meta.pk else: try: field = model._meta.get_field(part) except FieldDoesNotExist: # Handle the case where the field does not exist raise if field.is_relation: model = field.related_model else: # If the part is a non-relation field, break the loop break return model def get_textfield_paths(model): """ get all text field mapping / or relation """ paths = [] def traverse(model, prefix=""): for field in model._meta.get_fields(): if isinstance(field, django_models.TextField): paths.append( ( prefix + field.name, f"{(prefix.capitalize() + field.name.capitalize()).replace('__',' > ').replace('_id','').replace('_',' ')} (As a mail template)", ) ) elif isinstance(field, django_models.ForeignKey): traverse(field.related_model, prefix + field.name + "__") traverse(model) return paths