conflict issue

This commit is contained in:
ismail 2025-10-21 17:22:32 +03:00
parent 2dd90e4d38
commit ef8616c088
20 changed files with 367 additions and 435 deletions

View File

@ -135,9 +135,9 @@ WSGI_APPLICATION = 'NorahUniversity.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'haikal_db',
'USER': 'faheed',
'PASSWORD': 'Faheed@215',
'NAME': 'norahuniversity',
'USER': 'norahuniversity',
'PASSWORD': 'norahuniversity',
'HOST': '127.0.0.1',
'PORT': '5432',
}
@ -274,7 +274,6 @@ LINKEDIN_CLIENT_SECRET = 'WPL_AP1.QNH5lYnfRSQpp0Qp.GO8Srw=='
LINKEDIN_REDIRECT_URI = 'http://127.0.0.1:8000/jobs/linkedin/callback/'
Q_CLUSTER = {
'name': 'KAAUH_CLUSTER',
'workers': 8,

View File

@ -116,7 +116,7 @@ class JobPostingAdmin(admin.ModelAdmin):
'fields': ('internal_job_id', 'created_by', 'created_at', 'updated_at')
}),
('Integration', {
'fields': ('source', 'open_positions', 'position_number', 'reporting_to', 'start_date')
'fields': ('source', 'open_positions', 'position_number', 'reporting_to',)
}),
('LinkedIn Integration', {
'fields': ('posted_to_linkedin', 'linkedin_post_id', 'linkedin_post_url', 'linkedin_posted_at')

View File

@ -226,6 +226,7 @@ class JobPosting(Base):
parts.append(self.location_country)
return ", ".join(parts) if parts else "Not specified"
@property
def is_expired(self):
"""Check if application deadline has passed"""
if self.application_deadline:

View File

@ -7,10 +7,17 @@ from .models import FormField,FormStage,FormTemplate,Candidate,JobPosting
logger = logging.getLogger(__name__)
# @receiver(post_save, sender=JobPosting)
# def create_form_for_job(sender, instance, created, **kwargs):
# if created:
# FormTemplate.objects.create(job=instance, is_active=True, name=instance.title)
@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)
async_task(
'recruitment.tasks.format_job_description',
instance.pk,
# hook='myapp.tasks.email_sent_callback' # Optional callback
)
@receiver(post_save, sender=Candidate)
def score_candidate_resume(sender, instance, created, **kwargs):
if not instance.is_resume_parsed:
@ -75,238 +82,246 @@ def create_default_stages(sender, instance, created, **kwargs):
order=4,
is_predefined=True
)
# FormField.objects.create(
# stage=contact_stage,
# label='National ID / Iqama Number',
# field_type='text',
# required=False,
# order=5,
# is_predefined=True
# )
FormField.objects.create(
stage=contact_stage,
label='Resume Upload',
field_type='file',
required=True,
order=5,
order=6,
is_predefined=True,
file_types='.pdf,.doc,.docx',
max_file_size=1
)
# Stage 2: Resume Objective
objective_stage = FormStage.objects.create(
template=instance,
name='Resume Objective',
order=1,
is_predefined=True
)
FormField.objects.create(
stage=objective_stage,
label='Career Objective',
field_type='textarea',
required=False,
order=0,
is_predefined=True
)
# # Stage 2: Resume Objective
# objective_stage = FormStage.objects.create(
# template=instance,
# name='Resume Objective',
# order=1,
# is_predefined=True
# )
# FormField.objects.create(
# stage=objective_stage,
# label='Career Objective',
# field_type='textarea',
# required=False,
# order=0,
# is_predefined=True
# )
# Stage 3: Education
education_stage = FormStage.objects.create(
template=instance,
name='Education',
order=2,
is_predefined=True
)
FormField.objects.create(
stage=education_stage,
label='Degree',
field_type='text',
required=True,
order=0,
is_predefined=True
)
FormField.objects.create(
stage=education_stage,
label='Institution',
field_type='text',
required=True,
order=1,
is_predefined=True
)
FormField.objects.create(
stage=education_stage,
label='Location',
field_type='text',
required=False,
order=2,
is_predefined=True
)
FormField.objects.create(
stage=education_stage,
label='Graduation Date',
field_type='date',
required=False,
order=3,
is_predefined=True
)
# # Stage 3: Education
# education_stage = FormStage.objects.create(
# template=instance,
# name='Education',
# order=2,
# is_predefined=True
# )
# FormField.objects.create(
# stage=education_stage,
# label='Degree',
# field_type='text',
# required=True,
# order=0,
# is_predefined=True
# )
# FormField.objects.create(
# stage=education_stage,
# label='Institution',
# field_type='text',
# required=True,
# order=1,
# is_predefined=True
# )
# FormField.objects.create(
# stage=education_stage,
# label='Location',
# field_type='text',
# required=False,
# order=2,
# is_predefined=True
# )
# FormField.objects.create(
# stage=education_stage,
# label='Graduation Date',
# field_type='date',
# required=False,
# order=3,
# is_predefined=True
# )
# Stage 4: Experience
experience_stage = FormStage.objects.create(
template=instance,
name='Experience',
order=3,
is_predefined=True
)
FormField.objects.create(
stage=experience_stage,
label='Position Title',
field_type='text',
required=True,
order=0,
is_predefined=True
)
FormField.objects.create(
stage=experience_stage,
label='Company Name',
field_type='text',
required=True,
order=1,
is_predefined=True
)
FormField.objects.create(
stage=experience_stage,
label='Location',
field_type='text',
required=False,
order=2,
is_predefined=True
)
FormField.objects.create(
stage=experience_stage,
label='Start Date',
field_type='date',
required=True,
order=3,
is_predefined=True
)
FormField.objects.create(
stage=experience_stage,
label='End Date',
field_type='date',
required=True,
order=4,
is_predefined=True
)
FormField.objects.create(
stage=experience_stage,
label='Responsibilities & Achievements',
field_type='textarea',
required=False,
order=5,
is_predefined=True
)
# # Stage 4: Experience
# experience_stage = FormStage.objects.create(
# template=instance,
# name='Experience',
# order=3,
# is_predefined=True
# )
# FormField.objects.create(
# stage=experience_stage,
# label='Position Title',
# field_type='text',
# required=True,
# order=0,
# is_predefined=True
# )
# FormField.objects.create(
# stage=experience_stage,
# label='Company Name',
# field_type='text',
# required=True,
# order=1,
# is_predefined=True
# )
# FormField.objects.create(
# stage=experience_stage,
# label='Location',
# field_type='text',
# required=False,
# order=2,
# is_predefined=True
# )
# FormField.objects.create(
# stage=experience_stage,
# label='Start Date',
# field_type='date',
# required=True,
# order=3,
# is_predefined=True
# )
# FormField.objects.create(
# stage=experience_stage,
# label='End Date',
# field_type='date',
# required=True,
# order=4,
# is_predefined=True
# )
# FormField.objects.create(
# stage=experience_stage,
# label='Responsibilities & Achievements',
# field_type='textarea',
# required=False,
# order=5,
# is_predefined=True
# )
# Stage 5: Skills
skills_stage = FormStage.objects.create(
template=instance,
name='Skills',
order=4,
is_predefined=True
)
FormField.objects.create(
stage=skills_stage,
label='Technical Skills',
field_type='checkbox',
required=False,
order=0,
is_predefined=True,
options=['Programming Languages', 'Frameworks', 'Tools & Technologies']
)
# # Stage 5: Skills
# skills_stage = FormStage.objects.create(
# template=instance,
# name='Skills',
# order=4,
# is_predefined=True
# )
# FormField.objects.create(
# stage=skills_stage,
# label='Technical Skills',
# field_type='checkbox',
# required=False,
# order=0,
# is_predefined=True,
# options=['Programming Languages', 'Frameworks', 'Tools & Technologies']
# )
# Stage 6: Summary
summary_stage = FormStage.objects.create(
template=instance,
name='Summary',
order=5,
is_predefined=True
)
FormField.objects.create(
stage=summary_stage,
label='Professional Summary',
field_type='textarea',
required=False,
order=0,
is_predefined=True
)
# # Stage 6: Summary
# summary_stage = FormStage.objects.create(
# template=instance,
# name='Summary',
# order=5,
# is_predefined=True
# )
# FormField.objects.create(
# stage=summary_stage,
# label='Professional Summary',
# field_type='textarea',
# required=False,
# order=0,
# is_predefined=True
# )
# Stage 7: Certifications
certifications_stage = FormStage.objects.create(
template=instance,
name='Certifications',
order=6,
is_predefined=True
)
FormField.objects.create(
stage=certifications_stage,
label='Certification Name',
field_type='text',
required=False,
order=0,
is_predefined=True
)
FormField.objects.create(
stage=certifications_stage,
label='Issuing Organization',
field_type='text',
required=False,
order=1,
is_predefined=True
)
FormField.objects.create(
stage=certifications_stage,
label='Issue Date',
field_type='date',
required=False,
order=2,
is_predefined=True
)
FormField.objects.create(
stage=certifications_stage,
label='Expiration Date',
field_type='date',
required=False,
order=3,
is_predefined=True
)
# # Stage 7: Certifications
# certifications_stage = FormStage.objects.create(
# template=instance,
# name='Certifications',
# order=6,
# is_predefined=True
# )
# FormField.objects.create(
# stage=certifications_stage,
# label='Certification Name',
# field_type='text',
# required=False,
# order=0,
# is_predefined=True
# )
# FormField.objects.create(
# stage=certifications_stage,
# label='Issuing Organization',
# field_type='text',
# required=False,
# order=1,
# is_predefined=True
# )
# FormField.objects.create(
# stage=certifications_stage,
# label='Issue Date',
# field_type='date',
# required=False,
# order=2,
# is_predefined=True
# )
# FormField.objects.create(
# stage=certifications_stage,
# label='Expiration Date',
# field_type='date',
# required=False,
# order=3,
# is_predefined=True
# )
# Stage 8: Awards and Recognitions
awards_stage = FormStage.objects.create(
template=instance,
name='Awards and Recognitions',
order=7,
is_predefined=True
)
FormField.objects.create(
stage=awards_stage,
label='Award Name',
field_type='text',
required=False,
order=0,
is_predefined=True
)
FormField.objects.create(
stage=awards_stage,
label='Issuing Organization',
field_type='text',
required=False,
order=1,
is_predefined=True
)
FormField.objects.create(
stage=awards_stage,
label='Date Received',
field_type='date',
required=False,
order=2,
is_predefined=True
)
FormField.objects.create(
stage=awards_stage,
label='Description',
field_type='textarea',
required=False,
order=3,
is_predefined=True
)
# # Stage 8: Awards and Recognitions
# awards_stage = FormStage.objects.create(
# template=instance,
# name='Awards and Recognitions',
# order=7,
# is_predefined=True
# )
# FormField.objects.create(
# stage=awards_stage,
# label='Award Name',
# field_type='text',
# required=False,
# order=0,
# is_predefined=True
# )
# FormField.objects.create(
# stage=awards_stage,
# label='Issuing Organization',
# field_type='text',
# required=False,
# order=1,
# is_predefined=True
# )
# FormField.objects.create(
# stage=awards_stage,
# label='Date Received',
# field_type='date',
# required=False,
# order=2,
# is_predefined=True
# )
# FormField.objects.create(
# stage=awards_stage,
# label='Description',
# field_type='textarea',
# required=False,
# order=3,
# is_predefined=True
# )

View File

@ -26,11 +26,23 @@ except ImportError:
logger = logging.getLogger(__name__)
OPENROUTER_API_KEY ='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'
# OPENROUTER_MODEL = 'qwen/qwen-2.5-72b-instruct:free'
OPENROUTER_MODEL = 'openai/gpt-oss-20b:free'
OPENROUTER_MODEL = 'qwen/qwen-2.5-72b-instruct:free'
# OPENROUTER_MODEL = 'openai/gpt-oss-20b:free'
# OPENROUTER_MODEL = 'openai/gpt-oss-20b'
# OPENROUTER_MODEL = 'mistralai/mistral-small-3.2-24b-instruct:free'
# from google import genai
# client = genai.Client(api_key="AIzaSyDkwYmvRe5ieTjQi1ClSzD5z5roTwaFsmY")
# def google_ai(text):
# response = client.models.generate_content(
# model="gemini-2.5-flash", contents=text
# )
# return response
if not OPENROUTER_API_KEY:
logger.warning("OPENROUTER_API_KEY not set. Resume scoring will be skipped.")
@ -100,6 +112,43 @@ def extract_text_from_document(file_path):
else:
raise ValueError(f"Unsupported file type: {file_ext}. Only .pdf and .docx files are supported.")
def format_job_description(pk):
job_posting = JobPosting.objects.get(pk=pk)
print(job_posting)
prompt = f"""
Can you please organize and format this unformatted job description and qualifications into clear, readable sections using headings and bullet points?
Format the Content: You need to convert the clear, formatted job description and qualifications into a 2 blocks of HTML code.
**JOB DESCRIPTION:**
{job_posting.description}
**QUALIFICATIONS:**
{job_posting.qualifications}
**STRICT JSON OUTPUT INSTRUCTIONS:**
Output a single, valid JSON object with ONLY the following two top-level keys:
'job_description': 'A HTML containing the formatted job description',
'job_qualifications': 'A HTML containing the formatted job qualifications',
Do not include any other text except for the JSON output.
"""
result = ai_handler(prompt)
if result['status'] == 'error':
logger.error(f"AI handler returned error for candidate {job_posting.pk}")
print(f"AI handler returned error for candidate {job_posting.pk}")
return
data = result['data']
if isinstance(data, str):
data = json.loads(data)
print(data)
job_posting.description = data.get('job_description')
job_posting.qualifications = data.get('job_qualifications')
job_posting.save(update_fields=['description', 'qualifications'])
def ai_handler(prompt):
print("model call")
response = requests.post(
@ -133,143 +182,6 @@ def ai_handler(prompt):
return {"status": "error", "data": response.json()}
# def handle_reume_parsing_and_scoring(pk):
# from django.db import transaction
# logger.info(f"Scoring resume for candidate {pk}")
# instance = Candidate.objects.get(pk=pk)
# try:
# file_path = instance.resume.path
# with transaction.atomic():
# if not os.path.exists(file_path):
# logger.warning(f"Resume file not found: {file_path}")
# return
# resume_text = extract_text_from_pdf(file_path)
# job_detail= f"{instance.job.description} {instance.job.qualifications}"
# resume_parser_prompt = f"""
# You are an expert resume parser and summarizer. Given a resume in plain text format, extract and organize the following key-value information into a clean, valid JSON object:
# full_name: Full name of the candidate
# current_title: Most recent or current job title
# location: City and state (or country if outside the U.S.)
# contact: Phone number and email (as a single string or separate fields)
# linkedin: LinkedIn profile URL (if present)
# github: GitHub or portfolio URL (if present)
# summary: Brief professional profile or summary (12 sentences)
# education: List of degrees, each with:
# institution
# degree
# year
# gpa (if provided)
# relevant_courses (as a list, if mentioned)
# skills: Grouped by category if possible (e.g., programming, big data, visualization), otherwise as a flat list of technologies/tools
# experience: List of roles, each with:
# company
# job_title
# location
# start_date and end_date (or "Present" if applicable)
# key_achievements (as a list of concise bullet points)
# projects: List of notable projects (if clearly labeled), each with:
# name
# year
# technologies_used
# brief_description
# Instructions:
# Be concise but preserve key details.
# Normalize formatting (e.g., "Jun. 2014" → "2014-06").
# Omit redundant or promotional language.
# If a section is missing, omit the key or set it to null/empty list as appropriate.
# Output only valid JSON—no markdown, no extra text.
# Now, process the following resume text:
# {resume_text}
# """
# resume_parser_result = ai_handler(resume_parser_prompt)
# resume_scoring_prompt = f"""
# You are an expert technical recruiter. Your task is to score the following candidate for the role based on the provided job criteria.
# **Job Criteria:**
# {job_detail}
# **Candidate's Extracted Resume Json:**
# \"\"\"
# {resume_parser_result}
# \"\"\"
# **Your Task:**
# Provide a response in strict JSON format with the following keys:
# 1. 'match_score': A score from 0 to 100 representing how well the candidate fits the role.
# 2. 'strengths': A brief summary of why the candidate is a strong fit, referencing specific criteria.
# 3. 'weaknesses': A brief summary of where the candidate falls short or what criteria are missing.
# 4. 'years_of_experience': The total number of years of professional experience mentioned in the resume as a numerical value (e.g., 6.5).
# 5. 'criteria_checklist': An object where you rate the candidate's match for each specific criterion (e.g., {{'Python': 'Met', 'AWS': 'Not Mentioned'}}).
# 6. 'criteria_checklist': An object where you rate the candidate's match for each specific criterion (e.g., {{'Python': 'Met', 'AWS': 'Not Mentioned'}}).
# 7. 'category': Based on the content provided, determine the most fitting professional field or category for the individual. (e.g., {{"category" : "Data Science"}}) only output the category name and no other text example ('Software Development', 'correct') , ('Software Development and devops','wrong').
# 8. 'most_recent_job_title': The candidate's most recent or current professional job title.
# 9. 'recommendation': Provide a recommendation for the candidate (e.g., {{"recommendation": "
# Conclusion and Minor Considerations
# Overall Assessment: Highly Recommended Candidate.
# [Candidate] is an exceptionally strong candidate for this role. His proven track record with the core technology stack (Django, Python, Docker, CI/CD) and relevant experience in large-scale, high-impact enterprise projects (Telecom BPM/MDM) make him an excellent technical fit. His fluency in Arabic and English directly addresses a major non-negotiable requirement.
# The only minor area not explicitly mentioned is the mentoring aspect, but his senior level of experience and technical breadth strongly suggest he possesses the capability to mentor junior engineers.
# The hiring manager should move forward with this candidate with high confidence.
# ."}}).
# 10. 'top_3_keywords': A list of the three most dominant and relevant technical skills or technologies from the resume that match the job criteria.
# 11. 'job_fit_narrative': A single, concise sentence summarizing the core fit.
# 12. 'language_fluency': A list of languages and their fluency levels mentioned.
# 13. 'screening_stage_rating': A standardized rating (e.g., "A - Highly Qualified", "B - Qualified").
# 14. 'min_req_met_bool': Boolean (true/false) indicating if all non-negotiable minimum requirements are met.
# 15. 'soft_skills_score': A score (0-100) for inferred non-technical skills like leadership and communication.
# 16. 'experience_industry_match': A score (0-100) for the relevance of the candidate's industry experience.
# Only output valid JSON. Do not include any other text.
# """
# resume_scoring_result = ai_handler(resume_scoring_prompt)
# print(resume_scoring_result)
# instance.parsed_summary = str(resume_parser_result)
# # Core Scores
# instance.set_field('match_score', resume_scoring_result.get('match_score', 0)) # Set default for int
# instance.set_field('years_of_experience', resume_scoring_result.get('years_of_experience', 0.0)) # Set default for float
# instance.set_field('soft_skills_score', resume_scoring_result.get('soft_skills_score', 0))
# instance.set_field('experience_industry_match', resume_scoring_result.get('experience_industry_match', 0))
# # Screening & Funnel
# instance.set_field('min_req_met_bool', resume_scoring_result.get('min_req_met_bool', False)) # Set default for bool
# instance.set_field('screening_stage_rating', resume_scoring_result.get('screening_stage_rating', 'N/A'))
# instance.set_field('most_recent_job_title', resume_scoring_result.get('most_recent_job_title', 'N/A'))
# instance.set_field('top_3_keywords', resume_scoring_result.get('top_3_keywords', [])) # Set default for list
# # Summaries & Narrative
# instance.set_field('strengths', resume_scoring_result.get('strengths', ''))
# instance.set_field('weaknesses', resume_scoring_result.get('weaknesses', ''))
# instance.set_field('job_fit_narrative', resume_scoring_result.get('job_fit_narrative', ''))
# instance.set_field('recommendation', resume_scoring_result.get('recommendation', ''))
# # Structured Data
# instance.set_field('criteria_checklist', resume_scoring_result.get('criteria_checklist', {})) # Set default for dict
# instance.set_field('language_fluency', resume_scoring_result.get('language_fluency', [])) # Set default for list
# instance.set_field('category', resume_scoring_result.get('category', 'Uncategorized')) # Use 'category' key
# instance.is_resume_parsed = True
# instance.save(update_fields=['ai_analysis_data', 'is_resume_parsed','parsed_summary'])
# logger.info(f"Successfully scored resume for candidate {instance.id}")
# except Exception as e:
# instance.is_resume_parsed = False
# instance.save(update_fields=['is_resume_parsed'])
# logger.error(f"Failed to score resume for candidate:{instance.pk} {e}")
def safe_cast_to_float(value, default=0.0):
"""Safely converts a value (int, float, or string) to a float."""
if isinstance(value, (int, float)):

View File

@ -62,7 +62,7 @@ urlpatterns = [
# Form Preview URLs
# path('forms/', views.form_list, name='form_list'),
path('forms/builder/', views.form_builder, name='form_builder'),
path('forms/builder/<int:template_id>/', views.form_builder, name='form_builder'),
path('forms/builder/<slug:template_slug>/', views.form_builder, name='form_builder'),
path('forms/', views.form_templates_list, name='form_templates_list'),
path('forms/create-template/', views.create_form_template, name='create_form_template'),
@ -82,8 +82,8 @@ urlpatterns = [
path('htmx/<slug:slug>/candidate_update_status/', views.candidate_update_status, name='candidate_update_status'),
path('forms/form/<int:template_id>/submit/', views.submit_form, name='submit_form'),
path('forms/form/<int:template_id>/', views.form_wizard_view, name='form_wizard'),
path('forms/form/<slug:template_slug>/submit/', views.submit_form, name='submit_form'),
path('forms/form/<slug:template_slug>/', views.form_wizard_view, name='form_wizard'),
path('forms/<int:template_id>/submissions/<slug:slug>/', views.form_submission_details, name='form_submission_details'),
path('forms/template/<slug:slug>/submissions/', views.form_template_submissions_list, name='form_template_submissions_list'),
path('forms/template/<int:template_id>/all-submissions/', views.form_template_all_submissions, name='form_template_all_submissions'),
@ -96,6 +96,11 @@ urlpatterns = [
# path('api/forms/save/', views.save_form_builder, name='save_form_builder'),
# path('api/forms/<int:form_id>/load/', views.load_form, name='load_form'),
# path('api/forms/<int:form_id>/update/', views.update_form_builder, name='update_form_builder'),
path('api/templates/', views.list_form_templates, name='list_form_templates'),
path('api/templates/save/', views.save_form_template, name='save_form_template'),
path('api/templates/<int:template_id>/', views.load_form_template, name='load_form_template'),
path('api/templates/<int:template_id>/delete/', views.delete_form_template, name='delete_form_template'),
path('jobs/<slug:slug>/calendar/', views.interview_calendar_view, name='interview_calendar'),
path('jobs/<slug:slug>/calendar/interview/<int:interview_id>/', views.interview_detail_view, name='interview_detail'),

View File

@ -347,7 +347,6 @@ 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")
@ -633,12 +632,12 @@ def application_success(request,slug):
@ensure_csrf_cookie
@login_required
def form_builder(request, template_id=None):
def form_builder(request, template_slug=None):
"""Render the form builder interface"""
context = {}
if template_id:
if template_slug:
template = get_object_or_404(
FormTemplate, id=template_id, created_by=request.user
FormTemplate, slug=template_slug, created_by=request.user
)
context['template']=template
context["template_id"] = template.id
@ -762,7 +761,7 @@ def load_form_template(request, template_id):
def form_templates_list(request):
"""List all form templates for the current user"""
query = request.GET.get("q", "")
templates = FormTemplate.objects.filter(created_by=request.user)
templates = FormTemplate.objects.filter()
if query:
templates = templates.filter(
@ -802,7 +801,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(created_by=request.user).values(
templates = FormTemplate.objects.filter().values(
"id", "name", "description", "created_at", "updated_at"
)
return JsonResponse({"success": True, "templates": list(templates)})
@ -812,16 +811,16 @@ 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, created_by=request.user)
template = get_object_or_404(FormTemplate, id=template_id)
template.delete()
return JsonResponse(
{"success": True, "message": "Form template deleted successfully!"}
)
def form_wizard_view(request, template_id):
def form_wizard_view(request, template_slug):
"""Display the form as a step-by-step wizard"""
template = get_object_or_404(FormTemplate, pk=template_id, is_active=True)
template = get_object_or_404(FormTemplate, slug=template_slug, is_active=True)
job_id = template.job.internal_job_id
job=template.job
is_limit_exceeded = job.is_application_limit_reached
@ -831,7 +830,6 @@ def form_wizard_view(request, template_id):
'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,
@ -842,14 +840,15 @@ def form_wizard_view(request, template_id):
return render(
request,
"forms/form_wizard.html",
{"template_id": template_id, "job_id": job_id},
{"template_slug": template_slug, "job_id": job_id},
)
@require_POST
def submit_form(request, template_id):
def submit_form(request, template_slug):
"""Handle form submission"""
template = get_object_or_404(FormTemplate, id=template_id)
template = get_object_or_404(FormTemplate, slug=template_slug)
job = template.job
if request.method == "POST":
try:
with transaction.atomic():

View File

@ -74,17 +74,17 @@
<div class="card-footer bg-transparent">
<div class="btn-group w-100" role="group">
{% if form.created_by == user %}
<a href="{% url 'edit_form' form.id %}" class="btn btn-sm btn-outline-warning">
<a href="{% url 'edit_form' form.slug %}" class="btn btn-sm btn-outline-warning">
<i class="fas fa-edit"></i> Edit
</a>
{% endif %}
<a href="{% url 'form_preview' form.id %}" class="btn btn-sm btn-outline-primary" target="_blank">
<a href="{% url 'form_preview' form.slug %}" class="btn btn-sm btn-outline-primary" target="_blank">
<i class="fas fa-eye"></i> Preview
</a>
<a href="{% url 'form_embed' form.id %}" class="btn btn-sm btn-outline-secondary" target="_blank">
<a href="{% url 'form_embed' form.slug %}" class="btn btn-sm btn-outline-secondary" target="_blank">
<i class="fas fa-code"></i> Embed
</a>
<a href="{% url 'form_submissions' form.id %}" class="btn btn-sm btn-outline-info">
<a href="{% url 'form_submissions' form.slug %}" class="btn btn-sm btn-outline-info">
<i class="fas fa-list"></i> Submissions
</a>
</div>

View File

@ -231,10 +231,10 @@
<div class="mt-auto pt-2 border-top">
<div class="d-flex gap-2 justify-content-end">
<a href="{% url 'form_wizard' template.id %}" class="btn btn-outline-primary btn-sm" title="{% trans 'Preview' %}">
<a href="{% url 'form_wizard' template.slug %}" class="btn btn-outline-primary btn-sm" title="{% trans 'Preview' %}">
<i class="fas fa-eye"></i>
</a>
<a href="{% url 'form_builder' template.id %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}">
<a href="{% url 'form_builder' template.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Submissions' %}">
@ -286,10 +286,10 @@
<td>{{ template.updated_at|date:"M d, Y" }}</td>
<td class="text-end">
<div class="btn-group btn-group-sm" role="group">
<a href="{% url 'form_wizard' template.id %}" class="btn btn-outline-primary" title="{% trans 'Preview' %}">
<a href="{% url 'form_wizard' template.slug %}" class="btn btn-outline-primary" title="{% trans 'Preview' %}">
<i class="fas fa-eye"></i>
</a>
<a href="{% url 'form_builder' template.id %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<a href="{% url 'form_builder' template.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary" title="{% trans 'Submissions' %}">

View File

@ -538,7 +538,7 @@
const csrfToken = '{{ csrf_token }}';
const state = {
templateId: {{ template_id }},
templateId: {{ template_slug }},
stages: [],
currentStage: 0,
formData: {},

View File

@ -311,10 +311,10 @@
<td class="text-center">
<div class="btn-group btn-group-sm" role="group">
{% if job.form_template %}
<a href="{% url 'form_wizard' job.form_template.pk %}" class="btn btn-outline-secondary" title="{% trans 'Preview' %}">
<a href="{% url 'form_wizard' job.form_template.slug %}" class="btn btn-outline-secondary" title="{% trans 'Preview' %}">
<i class="fas fa-eye"></i>
</a>
<a href="{% url 'form_builder' job.form_template.id %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<a href="{% url 'form_builder' job.form_template.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<a href="{% url 'form_template_submissions_list' job.form_template.slug %}" class="btn btn-outline-secondary" title="{% trans 'Submissions' %}">

1
txt Normal file
View File

@ -0,0 +1 @@
Please Indicate the area that you are interested in the CV (ICU, OR, Medical Ward, Surgical Ward, Women`s Health). Bachelors degree in Nursing with minimum GPA (4 out of 5). SCFHS Nurse license classified as (Specialist). Country Specialist Nurse license. BLS Certified (ACLS, PALS, NALS dependent on unit requirement). Home Country equivalent Board Certifications must be maintained when appropriate. 2 year or more experience. Experience in same area. Key Accountabilities & Responsibilities Clinical: Is accountable for utilizing the nursing process, appropriate tools, evidence based knowledge, empathy and compassion in the assessment, planning, implementation and evaluation of nursing care for individual patients, while considering the individuals holistic needs and in accordance with scope of practice, hospital policy and procedure. Demonstrates the knowledge and skills, including critical thinking, necessary to implement the nursing plan of care, nursing interventions and procedures, as necessary for the care of the individual patient taking into consideration the patients condition, culture and medical plan of care. Advocates for patient by guiding best practice and standards of care within multidisciplinary team. Reports any deterioration in patients condition to physician, escalating via chain of command as necessary. Works towards reducing length of stay by advocating commencing discharge planning on admission. Is an advocate for patient safety, minimizes patient risk by ensuring a safe environment and conditions. Follows all policies and procedures, reporting observed or perceived risks in a timely fashion Suggests opportunities for improvement in care and in care environment. Uses transcultural awareness during all interactions with patients, families and colleagues. Works effectively with multidisciplinary team towards safe, effective and efficient patient outcomes. Maintains patient confidentiality according to policy. Ensures appropriate delegation of any duties when necessary. Takes appropriate action in emergencies. Documents all care accurately, completely and in a timely fashion. Demonstrates the computer skills necessary for carrying out duties. Education: Educates and informs patients and families on the care and management of condition, to adapt a problem-solving approach to managing and reporting complications. Provides health promotion and disease prevention advice. Participates in own and others education, training and professional development as needed. Shares appropriate, relevant and up to date information and knowledge with colleagues. Leadership: Utilizes leadership skills as nurse in charge of shift. Communicates effectively to ensure patient safety. Demonstrates knowledge of and follows all hospital related policies and procedures Reports potential or observed safety hazards immediately to supervisor, removes hazard or provides solution when possible. Reports any work-related risks such as equipment failures or resource insufficiencies to supervisor immediately. Uses communication and conflict negotiation skills to prevent and resolve complaints, reports through the chain of command as per hospital policy and procedure. Contributes to improving quality outcomes including patient and staff satisfaction indicators. Utilizes multidisciplinary team to ensure optimal patient experience. Exercises care in utilizing resources to maintain a cost efficient service. Actively participates in unit based meetings and councils. Supports a just culture, speaks up and promotes civility in the workplace. Research: Identifies opportunities for improvement that are evidence based. Maintains and shares up to date knowledge related to evidence based practice. Is involved in relevant projects related to practice, improvement and safety. Is actively involved in unit journal club. Hospital-wide: Respects patients and their families and promotes a patient-centered care culture. Participates and supports quality improvement and patient safety activities as an individual or as part of multidisciplinary teams. Performs other job-related duties as assigned.