diff --git a/NorahUniversity/__pycache__/settings.cpython-312.pyc b/NorahUniversity/__pycache__/settings.cpython-312.pyc index 160b1cf..42db791 100644 Binary files a/NorahUniversity/__pycache__/settings.cpython-312.pyc and b/NorahUniversity/__pycache__/settings.cpython-312.pyc differ diff --git a/NorahUniversity/__pycache__/urls.cpython-312.pyc b/NorahUniversity/__pycache__/urls.cpython-312.pyc index df79ce7..17d54d8 100644 Binary files a/NorahUniversity/__pycache__/urls.cpython-312.pyc and b/NorahUniversity/__pycache__/urls.cpython-312.pyc differ diff --git a/NorahUniversity/settings.py b/NorahUniversity/settings.py index 5c00084..d741e46 100644 --- a/NorahUniversity/settings.py +++ b/NorahUniversity/settings.py @@ -135,9 +135,9 @@ WSGI_APPLICATION = 'NorahUniversity.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'norahuniversity', - 'USER': 'norahuniversity', - 'PASSWORD': 'norahuniversity', + 'NAME': 'haikal_db', + 'USER': 'faheed', + 'PASSWORD': 'Faheed@215', 'HOST': '127.0.0.1', 'PORT': '5432', } diff --git a/NorahUniversity/urls.py b/NorahUniversity/urls.py index d4a3203..11de484 100644 --- a/NorahUniversity/urls.py +++ b/NorahUniversity/urls.py @@ -22,8 +22,8 @@ urlpatterns = [ # path('', include('recruitment.urls')), path("ckeditor5/", include('django_ckeditor_5.urls')), - path('/', views.form_wizard_view, name='form_wizard'), - path('/submit/', views.submit_form, name='submit_form'), + path('form_wizard//', views.form_wizard_view, name='form_wizard'), + path('form//submit/', views.submit_form, name='submit_form'), path('api/templates/', views.list_form_templates, name='list_form_templates'), path('api/templates/save/', views.save_form_template, name='save_form_template'), diff --git a/recruitment/__pycache__/admin.cpython-312.pyc b/recruitment/__pycache__/admin.cpython-312.pyc index 0b0a860..cd0678a 100644 Binary files a/recruitment/__pycache__/admin.cpython-312.pyc and b/recruitment/__pycache__/admin.cpython-312.pyc differ diff --git a/recruitment/__pycache__/forms.cpython-312.pyc b/recruitment/__pycache__/forms.cpython-312.pyc index 9725eb3..7d31dce 100644 Binary files a/recruitment/__pycache__/forms.cpython-312.pyc and b/recruitment/__pycache__/forms.cpython-312.pyc differ diff --git a/recruitment/__pycache__/linkedin_service.cpython-312.pyc b/recruitment/__pycache__/linkedin_service.cpython-312.pyc index c18ea68..0559ee7 100644 Binary files a/recruitment/__pycache__/linkedin_service.cpython-312.pyc and b/recruitment/__pycache__/linkedin_service.cpython-312.pyc differ diff --git a/recruitment/__pycache__/models.cpython-312.pyc b/recruitment/__pycache__/models.cpython-312.pyc index b0e0987..f54b6b9 100644 Binary files a/recruitment/__pycache__/models.cpython-312.pyc and b/recruitment/__pycache__/models.cpython-312.pyc differ diff --git a/recruitment/__pycache__/signals.cpython-312.pyc b/recruitment/__pycache__/signals.cpython-312.pyc index e9aa013..9bc8496 100644 Binary files a/recruitment/__pycache__/signals.cpython-312.pyc and b/recruitment/__pycache__/signals.cpython-312.pyc differ diff --git a/recruitment/__pycache__/urls.cpython-312.pyc b/recruitment/__pycache__/urls.cpython-312.pyc index 9534151..47958fa 100644 Binary files a/recruitment/__pycache__/urls.cpython-312.pyc and b/recruitment/__pycache__/urls.cpython-312.pyc differ diff --git a/recruitment/__pycache__/views.cpython-312.pyc b/recruitment/__pycache__/views.cpython-312.pyc index 19c121a..16fa8e9 100644 Binary files a/recruitment/__pycache__/views.cpython-312.pyc and b/recruitment/__pycache__/views.cpython-312.pyc differ diff --git a/recruitment/__pycache__/views_frontend.cpython-312.pyc b/recruitment/__pycache__/views_frontend.cpython-312.pyc index 329fd54..8806d1f 100644 Binary files a/recruitment/__pycache__/views_frontend.cpython-312.pyc and b/recruitment/__pycache__/views_frontend.cpython-312.pyc differ diff --git a/recruitment/forms.py b/recruitment/forms.py index 1794f3f..7d16b42 100644 --- a/recruitment/forms.py +++ b/recruitment/forms.py @@ -197,10 +197,10 @@ class JobPostingForm(forms.ModelForm): fields = [ 'title', 'department', 'job_type', 'workplace_type', 'location_city', 'location_state', 'location_country', - 'description', 'qualifications', 'salary_range', 'benefits','application_start_date' - ,'application_deadline', 'application_instructions', - 'position_number', 'reporting_to', 'joining_date', - 'created_by','open_positions','hash_tags','max_applications' + 'description', 'qualifications', 'salary_range', 'benefits', + 'application_deadline', 'application_instructions', + 'position_number', 'reporting_to', + 'open_positions','hash_tags','max_applications' ] widgets = { # Basic Information @@ -249,13 +249,11 @@ class JobPostingForm(forms.ModelForm): # 'placeholder': 'https://university.edu/careers/job123', # 'required': True # }), - 'application_start_date': forms.DateInput(attrs={ - 'class': 'form-control', - 'type': 'date' - }), + 'application_deadline': forms.DateInput(attrs={ 'class': 'form-control', - 'type': 'date' + 'type': 'date', + 'required':True }), 'open_positions': forms.NumberInput(attrs={ @@ -278,15 +276,8 @@ class JobPostingForm(forms.ModelForm): 'class': 'form-control', 'placeholder': 'Department Chair, Director, etc.' }), - 'joining_date': forms.DateInput(attrs={ - 'class': 'form-control', - 'type': 'date' - }), - - 'created_by': forms.TextInput(attrs={ - 'class': 'form-control', - 'placeholder': 'University Administrator' - }), + + 'max_applications': forms.NumberInput(attrs={ 'class': 'form-control', 'min': 1, @@ -296,19 +287,15 @@ class JobPostingForm(forms.ModelForm): def __init__(self,*args,**kwargs): - # Extract your custom argument BEFORE calling super() - self.is_anonymous_user = kwargs.pop('is_anonymous_user', False) # Now call the parent __init__ with remaining args super().__init__(*args, **kwargs) if not self.instance.pk:# Creating new job posting - if not self.is_anonymous_user: - self.fields['created_by'].initial = 'University Administrator' # self.fields['status'].initial = 'Draft' self.fields['location_city'].initial='Riyadh' self.fields['location_state'].initial='Riyadh Province' self.fields['location_country'].initial='Saudi Arabia' - + def clean_hash_tags(self): hash_tags=self.cleaned_data.get('hash_tags') diff --git a/recruitment/migrations/0001_initial.py b/recruitment/migrations/0001_initial.py index d0c43dc..bf6f650 100644 --- a/recruitment/migrations/0001_initial.py +++ b/recruitment/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.7 on 2025-10-21 11:27 +# Generated by Django 5.2.7 on 2025-10-21 22:26 import django.core.validators import django.db.models.deletion @@ -236,8 +236,8 @@ class Migration(migrations.Migration): ('salary_range', models.CharField(blank=True, help_text='e.g., $60,000 - $80,000', max_length=200)), ('benefits', django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True)), ('application_url', models.URLField(blank=True, help_text='URL where candidates apply', null=True, validators=[django.core.validators.URLValidator()])), - ('application_start_date', models.DateField(blank=True, null=True)), - ('application_deadline', models.DateField(blank=True, db_index=True, null=True)), + ('application_start_date', models.DateField()), + ('application_deadline', models.DateField(db_index=True)), ('application_instructions', django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True)), ('internal_job_id', models.CharField(editable=False, max_length=50, primary_key=True, serialize=False)), ('created_by', models.CharField(blank=True, help_text='Name of person who created this job', max_length=100)), @@ -251,7 +251,6 @@ class Migration(migrations.Migration): ('published_at', models.DateTimeField(blank=True, db_index=True, null=True)), ('position_number', models.CharField(blank=True, help_text='University position number', max_length=50)), ('reporting_to', models.CharField(blank=True, help_text='Who this position reports to', max_length=100)), - ('joining_date', models.DateField(blank=True, help_text='Desired start date', null=True)), ('open_positions', models.PositiveIntegerField(default=1, help_text='Number of open positions for this job')), ('max_applications', models.PositiveIntegerField(blank=True, default=1000, help_text='Maximum number of applications allowed', null=True)), ('cancel_reason', models.TextField(blank=True, help_text='Reason for canceling the job posting', verbose_name='Cancel Reason')), diff --git a/recruitment/migrations/0002_remove_jobposting_application_start_date.py b/recruitment/migrations/0002_remove_jobposting_application_start_date.py new file mode 100644 index 0000000..750027d --- /dev/null +++ b/recruitment/migrations/0002_remove_jobposting_application_start_date.py @@ -0,0 +1,17 @@ +# Generated by Django 5.2.7 on 2025-10-21 23:25 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('recruitment', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='jobposting', + name='application_start_date', + ), + ] diff --git a/recruitment/models.py b/recruitment/models.py index 91a1fb6..00a51ac 100644 --- a/recruitment/models.py +++ b/recruitment/models.py @@ -84,8 +84,8 @@ class JobPosting(Base): null=True, blank=True, ) - application_start_date=models.DateField(null=True, blank=True) - application_deadline = models.DateField(db_index=True, null=True, blank=True) # Added index + + application_deadline = models.DateField(db_index=True) # Added index application_instructions =CKEditor5Field( blank=True, null=True,config_name='extends' ) @@ -137,7 +137,7 @@ class JobPosting(Base): reporting_to = models.CharField( max_length=100, blank=True, help_text="Who this position reports to" ) - joining_date = models.DateField(null=True, blank=True, help_text="Desired start date") + open_positions = models.PositiveIntegerField( default=1, help_text="Number of open positions for this job" ) @@ -732,8 +732,10 @@ class FormTemplate(Base): blank=True, help_text="Description of the form template" ) created_by = models.ForeignKey( - User, on_delete=models.CASCADE, related_name="form_templates",null=True,blank=True, db_index=True - ) + User, on_delete=models.CASCADE, related_name="form_templates",null=True,blank=True, db_index=True + ) + # FIXME: on Delete model SETNULl + is_active = models.BooleanField( default=False, help_text="Whether this template is active" ) diff --git a/recruitment/signals.py b/recruitment/signals.py index ebc9f9b..2d1ed97 100644 --- a/recruitment/signals.py +++ b/recruitment/signals.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) @receiver(post_save, sender=JobPosting) def format_job(sender, instance, created, **kwargs): if created: - FormTemplate.objects.create(job=instance, is_active=True, name=instance.title) + # FormTemplate.objects.create(job=instance, is_active=True, name=instance.title) async_task( 'recruitment.tasks.format_job_description', instance.pk, diff --git a/recruitment/views.py b/recruitment/views.py index 73fc246..3c24c73 100644 --- a/recruitment/views.py +++ b/recruitment/views.py @@ -273,21 +273,12 @@ def create_job(request): if request.method == "POST": form = JobPostingForm( - request.POST, is_anonymous_user=not request.user.is_authenticated + request.POST ) # to check user is authenticated or not if form.is_valid(): try: job = form.save(commit=False) - if request.user.is_authenticated: - job.created_by = ( - request.user.get_full_name() or request.user.username - ) - else: - job.created_by = request.POST.get("created_by", "").strip() - if not job.created_by: - job.created_by = request.user.username - job.save() job_apply_url_relative=reverse('job_detail_candidate',kwargs={'slug':job.slug}) job_apply_url_absolute=request.build_absolute_uri(job_apply_url_relative) @@ -302,7 +293,7 @@ def create_job(request): else: messages.error(request, f"Please correct the errors below.{form.errors}") else: - form = JobPostingForm(is_anonymous_user=not request.user.is_authenticated) + form = JobPostingForm() return render(request, "jobs/create_job.html", {"form": form}) @@ -313,21 +304,11 @@ def edit_job(request, slug): if request.method == "POST": form = JobPostingForm( request.POST, - instance=job, - is_anonymous_user=not request.user.is_authenticated, + instance=job ) if form.is_valid(): try: - job = form.save(commit=False) - if request.user.is_authenticated: - job.created_by = ( - request.user.get_full_name() or request.user.username - ) - else: - job.created_by = request.POST.get("created_by", "").strip() - if not job.created_by: - job.created_by = "University Administrator" - job.save() + form.save() messages.success(request, f'Job "{job.title}" updated successfully!') return redirect("job_list") except Exception as e: @@ -338,7 +319,7 @@ def edit_job(request, slug): else: job = get_object_or_404(JobPosting, slug=slug) form = JobPostingForm( - instance=job, is_anonymous_user=not request.user.is_authenticated + instance=job ) return render(request, "jobs/edit_job.html", {"form": form, "job": job}) @@ -347,6 +328,7 @@ def edit_job(request, slug): def job_detail(request, slug): """View details of a specific job""" job = get_object_or_404(JobPosting, slug=slug) + # Get all candidates for this job, ordered by most recent applicants = job.candidates.all().order_by("-created_at") @@ -632,15 +614,15 @@ def application_success(request,slug): @ensure_csrf_cookie @login_required -def form_builder(request, template_slug=None): +def form_builder(request, template_id=None): """Render the form builder interface""" context = {} - if template_slug: + if template_id: template = get_object_or_404( - FormTemplate, slug=template_slug + FormTemplate, id=template_id, created_by=request.user ) context['template']=template - context["template_slug"] = template.slug + context["template_id"] = template.id context["template_name"] = template.name return render(request, "forms/form_builder.html", context) @@ -653,12 +635,12 @@ def save_form_template(request): data = json.loads(request.body) template_name = data.get("name", "Untitled Form") stages_data = data.get("stages", []) - template_slug = data.get("template_slug") + template_id = data.get("template_id") - if template_slug: + if template_id: # Update existing template template = get_object_or_404( - FormTemplate, slug=template_slug + FormTemplate, id=template_id, created_by=request.user ) template.name = template_name template.save() @@ -667,7 +649,7 @@ def save_form_template(request): else: # Create new template template = FormTemplate.objects.create( - name=template_name + name=template_name, created_by=request.user ) # Create stages and fields @@ -703,7 +685,7 @@ def save_form_template(request): return JsonResponse( { "success": True, - "template_slug": template.slug, + "template_id": template.id, "message": "Form template saved successfully!", } ) @@ -712,9 +694,9 @@ def save_form_template(request): @require_http_methods(["GET"]) -def load_form_template(request, template_slug): +def load_form_template(request, template_id): """Load an existing form template""" - template = get_object_or_404(FormTemplate, slug=template_slug) + template = get_object_or_404(FormTemplate, id=template_id, created_by=request.user) stages = [] for stage in template.stages.all(): @@ -747,7 +729,6 @@ def load_form_template(request, template_slug): "success": True, "template": { "id": template.id, - "template_slug": template.slug, "name": template.name, "description": template.description, "is_active": template.is_active, @@ -762,7 +743,7 @@ def load_form_template(request, template_slug): def form_templates_list(request): """List all form templates for the current user""" query = request.GET.get("q", "") - templates = FormTemplate.objects.filter() + templates = FormTemplate.objects.filter(created_by=request.user) if query: templates = templates.filter( @@ -802,7 +783,7 @@ def create_form_template(request): @require_http_methods(["GET"]) def list_form_templates(request): """List all form templates for the current user""" - templates = FormTemplate.objects.filter().values( + templates = FormTemplate.objects.filter(created_by=request.user).values( "id", "name", "description", "created_at", "updated_at" ) return JsonResponse({"success": True, "templates": list(templates)}) @@ -812,25 +793,26 @@ def list_form_templates(request): @require_http_methods(["DELETE"]) def delete_form_template(request, template_id): """Delete a form template""" - template = get_object_or_404(FormTemplate, id=template_id) + template = get_object_or_404(FormTemplate, id=template_id, created_by=request.user) template.delete() return JsonResponse( {"success": True, "message": "Form template deleted successfully!"} ) -def form_wizard_view(request, template_slug): +def form_wizard_view(request, template_id): """Display the form as a step-by-step wizard""" - template = get_object_or_404(FormTemplate, slug=template_slug, is_active=True) + template = get_object_or_404(FormTemplate, pk=template_id, is_active=True) job_id = template.job.internal_job_id job=template.job - is_limit_exceeded = job.is_application_limit_reached + is_limit_exceeded=job.is_application_limit_reached if is_limit_exceeded: messages.error( request, 'Application limit reached: This job is no longer accepting new applications. Please explore other available positions.' ) return redirect('job_detail_candidate',slug=job.slug) + if job.is_expired: messages.error( request, @@ -841,16 +823,14 @@ def form_wizard_view(request, template_slug): return render( request, "forms/form_wizard.html", - {"template_slug": template_slug, "job_id": job_id}, + {"template_id": template_id, "job_id": job_id}, ) -@csrf_exempt @require_POST -def submit_form(request, template_slug): +def submit_form(request, template_id): """Handle form submission""" - template = get_object_or_404(FormTemplate, slug=template_slug) - job = template.job + template = get_object_or_404(FormTemplate, id=template_id) if request.method == "POST": try: with transaction.atomic(): @@ -864,7 +844,6 @@ def submit_form(request, template_slug): {"success": False, "message": "Application limit reached for this job."} ) submission = FormSubmission.objects.create(template=template) - # Process field responses for field_id, value in request.POST.items(): if field_id.startswith("field_"): @@ -909,7 +888,7 @@ def submit_form(request, template_slug): ) submission.applicant_email = email.display_value submission.save() - # time=timezone.now() + time=timezone.now() Candidate.objects.create( first_name=first_name.display_value, last_name=last_name.display_value, @@ -917,16 +896,10 @@ def submit_form(request, template_slug): phone=phone.display_value, address=address.display_value, resume=resume.get_file if resume.is_file else None, - job=job + job=submission.template.job, + ) - return JsonResponse( - { - "success": True, - "message": "Form submitted successfully!", - "redirect_url": reverse('application_success',kwargs={'slug':job.slug}), - } - ) - # return redirect('application_success',slug=job.slug) + return redirect('application_success',slug=job.slug) except Exception as e: logger.error(f"Candidate creation failed,{e}") @@ -2071,6 +2044,7 @@ def user_detail(request, pk): user = get_object_or_404(User, pk=pk) try: + profile_instance = user.profile profile_form = ProfileImageUploadForm(instance=profile_instance) except: @@ -2224,10 +2198,6 @@ def account_toggle_status(request,pk): messages.error(f'Please correct the error below') -@login_required -def user_detail(requests,pk): - user=get_object_or_404(User,pk=pk) - return render(requests,'user/profile.html') @csrf_exempt diff --git a/recruitment/views_frontend.py b/recruitment/views_frontend.py index 50c05e3..61d5fa2 100644 --- a/recruitment/views_frontend.py +++ b/recruitment/views_frontend.py @@ -394,6 +394,27 @@ def dashboard_view(request): ).count() high_potential_ratio = round((high_potential_count / total_candidates) * 100, 1) if total_candidates > 0 else 0 + #donut chart data + jobs=models.JobPosting.objects.all() + selected_job_id=request.GET.get('selected_job_id') + print(jobs) + print(selected_job_id) + apply_counts,exam_counts,interview_counts,offer_counts=[0]*4 + if selected_job_id: + job=jobs.filter(internal_job_id=selected_job_id) + apply_counts=job.screening_candidates_count or 0 + exam_counts=job.exam_candidates_count or 0 + interview_counts=job.interview_candidates_count or 0 + offer_counts=job.offer_candidates_count or 0 + + + + + applicant_stages=['APPLIED','EXAM','INTERVIEW','OFFER'] + stage_counts=[apply_counts,exam_counts,interview_counts,offer_counts] + + + context = { 'total_jobs': total_jobs, @@ -409,8 +430,13 @@ def dashboard_view(request): 'high_potential_count': high_potential_count, 'high_potential_ratio': high_potential_ratio, 'scored_ratio': scored_ratio, + 'applicant_stages':json.dumps(applicant_stages), + 'stage_counts':json.dumps(stage_counts), + 'jobs':'jobs', + 'selected_job_id':selected_job_id } return render(request, 'recruitment/dashboard.html', context) + @login_required def candidate_offer_view(request, slug): """View for candidates in the Offer stage""" diff --git a/templates/base.html b/templates/base.html index 0250f32..b4a6c35 100644 --- a/templates/base.html +++ b/templates/base.html @@ -16,9 +16,9 @@ {% endif %} - + - + @@ -120,7 +120,7 @@ {% endif %}
@@ -323,21 +332,20 @@
- + - -
+ +
{% trans "Financial & Timeline" %}
@@ -392,19 +400,74 @@
{{ job.benefits|safe}}
{% endif %} - - - {# TAB 3 CONTENT: APPLICATION INSTRUCTIONS #} - {% if job.application_instructions %} -
-
+ {% if job.application_instructions %} +
{% trans "Application Instructions" %}
{{ job.application_instructions|safe }}
-
- {% endif %} + {% endif %} +
+ + {# TAB 3 CONTENT: APPLICATION KPIS #} +
+
+ + {# 1. Job Avg. Score #} +
+
+
+ +
{{ avg_match_score|floatformat:1 }}
+ {% trans "Avg. AI Score" %} +
+
+
+ + {# 2. High Potential Count #} +
+
+
+ +
{{ high_potential_count }}
+ {% trans "High Potential" %} +
+
+
+ + {# 3. Avg. Time to Interview #} +
+
+
+ +
{{ avg_t2i_days|floatformat:1 }}d
+ {% trans "Time to Interview" %} +
+
+
+ + {# 4. Avg. Exam Review Time #} +
+
+
+ +
{{ avg_t_in_exam_days|floatformat:1 }}d
+ {% trans "Avg. Exam Review" %} +
+
+
+
+ +

+ {% trans "KPIs based on completed applicant data." %} +

+ +
+ + + + {# FOOTER ACTIONS #} @@ -423,7 +486,7 @@ {# RIGHT COLUMN: TABBED CARDS #} -
+
{# New Card for Candidate Category Chart #}
@@ -440,44 +503,9 @@
-
-
-
{% trans "Applicant Tracking" %}
- {% include 'jobs/partials/applicant_tracking.html' %} -
-
- -
-
-
-

{% trans "Job Avg. Score" %}

-
-
{{ avg_match_score|floatformat:1 }}
-
{% trans "Average AI Match Score (0-100)" %}
-
-
-
-

{% trans "High Potential Count" %}

-
-
{{ high_potential_count }}
-
{% trans "Candidates with Score ≥ 75%" %}
-
-
-
-

{% trans "Avg. Time to Interview" %}

-
-
{{ avg_t2i_days|floatformat:1 }}d
-
{% trans "Applied to Interview (Total Funnel Speed)" %}
-
-
-
-

{% trans "Avg. Exam Review Time" %}

-
-
{{ avg_t_in_exam_days|floatformat:1 }}d
-
{% trans "Days spent between Exam and Interview" %}
-
-
-
+ {# REMOVED: Standalone Applicant Tracking Card (It is now in a tab) #} + +
{# RIGHT TABS NAVIGATION #} @@ -503,35 +536,7 @@ {# TAB 1: APPLICANTS CONTENT #}
{% trans "Total Applicants" %} ({{ total_applicants }})
- {% comment %} {% if total_applicants > 0 %} -
-
-
-
{{ applied_count }}
- {% trans "Applied" %} -
-
-
-
-
{{ interview_count }}
- {% trans "Interview" %} -
-
-
-
-
{{ offer_count }}
- {% trans "Offer" %} -
-
-
- - - {% endif %} {% endcomment %} - +
- {# TAB 2: MANAGEMENT (LinkedIn & Forms) CONTENT #} + {# NEW TAB 2: APPLICANT TRACKING CONTENT #} +
+
{% trans "Pipeline Stages" %}
+ {% include 'jobs/partials/applicant_tracking.html' %} +

{% trans "View the number of candidates currently in each stage of the hiring pipeline." %}

+
+ + {# TAB 3: MANAGEMENT (Form Template) CONTENT #}
- {# LinkedIn Integration (Content from old card) #} - - - {# Applicant Form Management (Content from old card) #}
{% trans "Form Management" %}

@@ -569,8 +577,8 @@

- {# TAB 3: INTERNAL INFO CONTENT #} -
- - {# TAB 3: INTERNAL INFO CONTENT #} -
-
{% trans "Internal Information" %}
-
-

{% trans "Internal Job ID:" %} {{ job.internal_job_id }}

-

{% trans "Created:" %} {{ job.created_at|date:"M d, Y" }}

-

{% trans "Last Updated:" %} {{ job.updated_at|date:"M d, Y" }}

- {% if job.reporting_to %} -

{% trans "Reports To:" %} {{ job.reporting_to }}

- {% endif %} -
- -
@@ -660,10 +626,8 @@
- {% include "jobs/partials/image_upload.html" %} -