2025-08-12 13:33:25 +03:00

544 lines
25 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{% if form.instance.pk %}Edit{% else %}Create{% endif %} Audit - Quality Management{% endblock %}
{% block content %}
<!-- BEGIN breadcrumb -->
<ol class="breadcrumb float-xl-end">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'quality:dashboard' %}">Quality</a></li>
<li class="breadcrumb-item"><a href="{% url 'quality:audit_list' %}">Audits</a></li>
<li class="breadcrumb-item active">{% if form.instance.pk %}Edit{% else %}Create{% endif %} Audit</li>
</ol>
<!-- END breadcrumb -->
<!-- BEGIN page-header -->
<h1 class="page-header">
{% if form.instance.pk %}Edit Audit{% else %}Create Quality Audit{% endif %}
<small>{% if form.instance.pk %}Update audit information{% else %}Schedule a new quality audit{% endif %}</small>
</h1>
<!-- END page-header -->
<!-- BEGIN row -->
<div class="row">
<div class="col-xl-8">
<!-- Main Form -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Audit Information</h4>
<div class="panel-heading-btn">
<button type="button" class="btn btn-secondary btn-sm" onclick="saveDraft()">
<i class="fa fa-save me-1"></i>Save Draft
</button>
</div>
</div>
<div class="panel-body">
<form method="post" id="auditForm" novalidate>
{% csrf_token %}
<!-- Basic Information -->
<div class="row">
<div class="col-md-8">
<div class="form-floating mb-3">
{{ form.title }}
<label for="{{ form.title.id_for_label }}">Audit Title *</label>
{% if form.title.errors %}
<div class="invalid-feedback d-block">{{ form.title.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating mb-3">
{{ form.audit_type }}
<label for="{{ form.audit_type.id_for_label }}">Audit Type *</label>
{% if form.audit_type.errors %}
<div class="invalid-feedback d-block">{{ form.audit_type.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<div class="form-floating mb-3">
{{ form.description }}
<label for="{{ form.description.id_for_label }}">Description</label>
{% if form.description.errors %}
<div class="invalid-feedback d-block">{{ form.description.errors.0 }}</div>
{% endif %}
</div>
<div class="form-floating mb-3">
{{ form.scope }}
<label for="{{ form.scope.id_for_label }}">Audit Scope</label>
{% if form.scope.errors %}
<div class="invalid-feedback d-block">{{ form.scope.errors.0 }}</div>
{% endif %}
<div class="form-text">Define what areas, processes, or departments will be audited</div>
</div>
<!-- Scheduling -->
<h6 class="mt-4 mb-3">Scheduling Information</h6>
<div class="row">
<div class="col-md-4">
<div class="form-floating mb-3">
{{ form.scheduled_date }}
<label for="{{ form.scheduled_date.id_for_label }}">Scheduled Date</label>
{% if form.scheduled_date.errors %}
<div class="invalid-feedback d-block">{{ form.scheduled_date.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating mb-3">
{{ form.estimated_duration }}
<label for="{{ form.estimated_duration.id_for_label }}">Estimated Duration (days)</label>
{% if form.estimated_duration.errors %}
<div class="invalid-feedback d-block">{{ form.estimated_duration.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating mb-3">
{{ form.priority }}
<label for="{{ form.priority.id_for_label }}">Priority</label>
{% if form.priority.errors %}
<div class="invalid-feedback d-block">{{ form.priority.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<!-- Department and Team -->
<h6 class="mt-4 mb-3">Department and Team</h6>
<div class="row">
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.department }}
<label for="{{ form.department.id_for_label }}">Department</label>
{% if form.department.errors %}
<div class="invalid-feedback d-block">{{ form.department.errors.0 }}</div>
{% endif %}
<div class="form-text">Leave blank for organization-wide audits</div>
</div>
</div>
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.lead_auditor }}
<label for="{{ form.lead_auditor.id_for_label }}">Lead Auditor</label>
{% if form.lead_auditor.errors %}
<div class="invalid-feedback d-block">{{ form.lead_auditor.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<!-- Team Members -->
<div class="mb-3">
<label class="form-label">Audit Team Members</label>
<div id="teamMembersContainer">
{% if form.instance.pk %}
{% for member in form.instance.team_members.all %}
<div class="d-flex align-items-center mb-2 team-member-row">
<select class="form-select me-2" name="team_members">
<option value="">Select team member</option>
{% for user in available_users %}
<option value="{{ user.id }}" {% if user.id == member.id %}selected{% endif %}>
{{ user.get_full_name }} - {{ user.email }}
</option>
{% endfor %}
</select>
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeTeamMember(this)">
<i class="fa fa-times"></i>
</button>
</div>
{% endfor %}
{% endif %}
</div>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addTeamMember()">
<i class="fa fa-plus me-1"></i>Add Team Member
</button>
</div>
<!-- Standards and Criteria -->
<h6 class="mt-4 mb-3">Audit Standards and Criteria</h6>
<div class="form-floating mb-3">
{{ form.standards }}
<label for="{{ form.standards.id_for_label }}">Applicable Standards</label>
{% if form.standards.errors %}
<div class="invalid-feedback d-block">{{ form.standards.errors.0 }}</div>
{% endif %}
<div class="form-text">List relevant standards, regulations, or policies (e.g., ISO 9001, Joint Commission, etc.)</div>
</div>
<div class="form-floating mb-3">
{{ form.criteria }}
<label for="{{ form.criteria.id_for_label }}">Audit Criteria</label>
{% if form.criteria.errors %}
<div class="invalid-feedback d-block">{{ form.criteria.errors.0 }}</div>
{% endif %}
<div class="form-text">Specific criteria or requirements to be evaluated</div>
</div>
<!-- Objectives -->
<h6 class="mt-4 mb-3">Audit Objectives</h6>
<div class="form-floating mb-3">
{{ form.objectives }}
<label for="{{ form.objectives.id_for_label }}">Objectives</label>
{% if form.objectives.errors %}
<div class="invalid-feedback d-block">{{ form.objectives.errors.0 }}</div>
{% endif %}
<div class="form-text">What the audit aims to achieve or verify</div>
</div>
<!-- Methodology -->
<h6 class="mt-4 mb-3">Audit Methodology</h6>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Audit Methods</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="methods" value="document_review" id="method1">
<label class="form-check-label" for="method1">Document Review</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="methods" value="interviews" id="method2">
<label class="form-check-label" for="method2">Staff Interviews</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="methods" value="observation" id="method3">
<label class="form-check-label" for="method3">Direct Observation</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="methods" value="testing" id="method4">
<label class="form-check-label" for="method4">Process Testing</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="methods" value="sampling" id="method5">
<label class="form-check-label" for="method5">Statistical Sampling</label>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-floating mb-3">
{{ form.sampling_method }}
<label for="{{ form.sampling_method.id_for_label }}">Sampling Method</label>
{% if form.sampling_method.errors %}
<div class="invalid-feedback d-block">{{ form.sampling_method.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<!-- Additional Information -->
<h6 class="mt-4 mb-3">Additional Information</h6>
<div class="form-floating mb-3">
{{ form.special_requirements }}
<label for="{{ form.special_requirements.id_for_label }}">Special Requirements</label>
{% if form.special_requirements.errors %}
<div class="invalid-feedback d-block">{{ form.special_requirements.errors.0 }}</div>
{% endif %}
<div class="form-text">Any special access, equipment, or preparation needed</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-check mb-3">
{{ form.is_regulatory }}
<label class="form-check-label" for="{{ form.is_regulatory.id_for_label }}">
Regulatory Audit
</label>
<div class="form-text">Check if this is a regulatory compliance audit</div>
</div>
</div>
<div class="col-md-6">
<div class="form-check mb-3">
{{ form.is_external }}
<label class="form-check-label" for="{{ form.is_external.id_for_label }}">
External Audit
</label>
<div class="form-text">Check if conducted by external auditors</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="d-flex justify-content-between mt-4">
<div>
<a href="{% if form.instance.pk %}{% url 'quality:audit_detail' form.instance.pk %}{% else %}{% url 'quality:audit_list' %}{% endif %}" class="btn btn-secondary">
<i class="fa fa-times me-2"></i>Cancel
</a>
</div>
<div>
<button type="button" class="btn btn-outline-primary me-2" onclick="saveDraft()">
<i class="fa fa-save me-2"></i>Save Draft
</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-check me-2"></i>{% if form.instance.pk %}Update{% else %}Create{% endif %} Audit
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="col-xl-4">
<!-- Help and Guidelines -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Audit Guidelines</h4>
</div>
<div class="panel-body">
<div class="alert alert-info">
<h6><i class="fa fa-info-circle me-2"></i>Audit Planning Tips</h6>
<ul class="mb-0 small">
<li>Define clear objectives and scope</li>
<li>Select qualified audit team members</li>
<li>Allow adequate time for preparation</li>
<li>Communicate with auditees in advance</li>
<li>Prepare audit checklists and tools</li>
</ul>
</div>
<div class="alert alert-warning">
<h6><i class="fa fa-exclamation-triangle me-2"></i>Important Notes</h6>
<ul class="mb-0 small">
<li>Regulatory audits require special preparation</li>
<li>External audits may need additional coordination</li>
<li>Ensure all team members are available</li>
<li>Consider operational impact when scheduling</li>
</ul>
</div>
</div>
</div>
<!-- Audit Checklist -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Pre-Audit Checklist</h4>
</div>
<div class="panel-body">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="check1">
<label class="form-check-label small" for="check1">
Audit objectives defined
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="check2">
<label class="form-check-label small" for="check2">
Scope clearly documented
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="check3">
<label class="form-check-label small" for="check3">
Lead auditor assigned
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="check4">
<label class="form-check-label small" for="check4">
Team members selected
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="check5">
<label class="form-check-label small" for="check5">
Standards and criteria identified
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="check6">
<label class="form-check-label small" for="check6">
Schedule coordinated with department
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="check7">
<label class="form-check-label small" for="check7">
Audit tools and checklists prepared
</label>
</div>
</div>
</div>
<!-- Recent Audits -->
{% if recent_audits %}
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Recent Audits</h4>
</div>
<div class="panel-body">
{% for audit in recent_audits %}
<div class="d-flex align-items-center mb-2">
<div class="flex-fill">
<div class="fw-bold small">{{ audit.title|truncatechars:30 }}</div>
<div class="text-muted small">{{ audit.scheduled_date|date:"M d, Y" }}</div>
</div>
<div>
{% if audit.status == 'completed' %}
<span class="badge bg-success">Completed</span>
{% elif audit.status == 'in_progress' %}
<span class="badge bg-info">In Progress</span>
{% else %}
<span class="badge bg-secondary">{{ audit.get_status_display }}</span>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
</div>
<!-- END row -->
{% endblock %}
{% block js %}
<script>
$(document).ready(function() {
// Auto-save functionality
let autoSaveTimer;
$('#auditForm input, #auditForm textarea, #auditForm select').on('input change', function() {
clearTimeout(autoSaveTimer);
autoSaveTimer = setTimeout(function() {
saveDraft(true); // Silent save
}, 30000); // Auto-save after 30 seconds of inactivity
});
// Form validation
$('#auditForm').on('submit', function(e) {
if (!validateForm()) {
e.preventDefault();
return false;
}
});
// Load saved methods if editing
{% if form.instance.pk and form.instance.methods %}
const savedMethods = '{{ form.instance.methods }}'.split(',');
savedMethods.forEach(function(method) {
$('input[name="methods"][value="' + method.trim() + '"]').prop('checked', true);
});
{% endif %}
});
function addTeamMember() {
const container = $('#teamMembersContainer');
const newRow = $(`
<div class="d-flex align-items-center mb-2 team-member-row">
<select class="form-select me-2" name="team_members">
<option value="">Select team member</option>
{% for user in available_users %}
<option value="{{ user.id }}">{{ user.get_full_name }} - {{ user.email }}</option>
{% endfor %}
</select>
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeTeamMember(this)">
<i class="fa fa-times"></i>
</button>
</div>
`);
container.append(newRow);
}
function removeTeamMember(button) {
$(button).closest('.team-member-row').remove();
}
function validateForm() {
let isValid = true;
// Clear previous errors
$('.is-invalid').removeClass('is-invalid');
// Required field validation
const requiredFields = ['{{ form.title.id_for_label }}', '{{ form.audit_type.id_for_label }}'];
requiredFields.forEach(function(fieldId) {
const field = $('#' + fieldId);
if (!field.val().trim()) {
field.addClass('is-invalid');
isValid = false;
}
});
// Date validation
const scheduledDate = $('#{{ form.scheduled_date.id_for_label }}').val();
if (scheduledDate && new Date(scheduledDate) < new Date()) {
$('#{{ form.scheduled_date.id_for_label }}').addClass('is-invalid');
toastr.error('Scheduled date cannot be in the past');
isValid = false;
}
if (!isValid) {
toastr.error('Please correct the highlighted fields');
}
return isValid;
}
function saveDraft(silent = false) {
const formData = new FormData($('#auditForm')[0]);
// Add selected methods
const methods = [];
$('input[name="methods"]:checked').each(function() {
methods.push($(this).val());
});
formData.append('methods', methods.join(','));
// Add team members
const teamMembers = [];
$('select[name="team_members"]').each(function() {
if ($(this).val()) {
teamMembers.push($(this).val());
}
});
formData.append('team_members_list', JSON.stringify(teamMembers));
formData.append('save_draft', 'true');
$.ajax({
url: window.location.href,
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (!silent) {
toastr.success('Draft saved successfully');
}
},
error: function() {
if (!silent) {
toastr.error('Failed to save draft');
}
}
});
}
// Update checklist based on form completion
function updateChecklist() {
$('#check1').prop('checked', $('#{{ form.objectives.id_for_label }}').val().trim() !== '');
$('#check2').prop('checked', $('#{{ form.scope.id_for_label }}').val().trim() !== '');
$('#check3').prop('checked', $('#{{ form.lead_auditor.id_for_label }}').val() !== '');
$('#check4').prop('checked', $('select[name="team_members"]').length > 0);
$('#check5').prop('checked', $('#{{ form.standards.id_for_label }}').val().trim() !== '');
$('#check6').prop('checked', $('#{{ form.scheduled_date.id_for_label }}').val() !== '');
}
// Update checklist when form changes
$('#auditForm input, #auditForm textarea, #auditForm select').on('input change', function() {
setTimeout(updateChecklist, 100);
});
// Initial checklist update
$(document).ready(function() {
updateChecklist();
});
</script>
{% endblock %}