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

649 lines
31 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{% if object %}Edit {{ object.name }}{% else %}Add Supplier{% endif %} - {{ block.super }}{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Page Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1 class="h3 mb-1">
<i class="fas fa-truck me-2"></i>{% if object %}Edit Supplier{% else %}Add New Supplier{% endif %}
</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb mb-0">
<li class="breadcrumb-item"><a href="{% url 'inventory:dashboard' %}">Inventory</a></li>
<li class="breadcrumb-item"><a href="{% url 'inventory:supplier_list' %}">Suppliers</a></li>
{% if object %}
<li class="breadcrumb-item"><a href="{% url 'inventory:supplier_detail' object.pk %}">{{ object.name }}</a></li>
<li class="breadcrumb-item active">Edit</li>
{% else %}
<li class="breadcrumb-item active">Add New</li>
{% endif %}
</ol>
</nav>
</div>
<div class="btn-group">
<a href="{% if object %}{% url 'inventory:supplier_detail' object.pk %}{% else %}{% url 'inventory:supplier_list' %}{% endif %}"
class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-2"></i>Back
</a>
{% if object %}
<a href="{% url 'inventory:supplier_detail' object.pk %}" class="btn btn-outline-info">
<i class="fas fa-eye me-2"></i>View Details
</a>
{% endif %}
</div>
</div>
<div class="row">
<!-- Main Form -->
<div class="col-lg-8">
<form method="post" id="supplierForm" novalidate>
{% csrf_token %}
<!-- Basic Information -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-info-circle me-2"></i>Basic Information
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label for="{{ form.supplier_code.id_for_label }}" class="form-label">
Supplier Code <span class="text-danger">*</span>
</label>
{{ form.supplier_code }}
{% if form.supplier_code.errors %}
<div class="invalid-feedback d-block">
{{ form.supplier_code.errors.0 }}
</div>
{% endif %}
<div class="form-text">Unique identifier for the supplier</div>
</div>
<div class="col-md-6 mb-3">
<label for="{{ form.name.id_for_label }}" class="form-label">
Supplier Name <span class="text-danger">*</span>
</label>
{{ form.name }}
{% if form.name.errors %}
<div class="invalid-feedback d-block">
{{ form.name.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="{{ form.supplier_type.id_for_label }}" class="form-label">
Supplier Type <span class="text-danger">*</span>
</label>
{{ form.supplier_type }}
{% if form.supplier_type.errors %}
<div class="invalid-feedback d-block">
{{ form.supplier_type.errors.0 }}
</div>
{% endif %}
</div>
<div class="col-md-6 mb-3">
<label for="{{ form.is_active.id_for_label }}" class="form-label">Status</label>
<div class="form-check form-switch">
{{ form.is_active }}
<label class="form-check-label" for="{{ form.is_active.id_for_label }}">
Active Supplier
</label>
</div>
{% if form.is_active.errors %}
<div class="invalid-feedback d-block">
{{ form.is_active.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="mb-3">
<label for="{{ form.description.id_for_label }}" class="form-label">Description</label>
{{ form.description }}
{% if form.description.errors %}
<div class="invalid-feedback d-block">
{{ form.description.errors.0 }}
</div>
{% endif %}
<div class="form-text">Brief description of the supplier and their services</div>
</div>
</div>
</div>
<!-- Contact Information -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-address-book me-2"></i>Contact Information
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label for="{{ form.contact_person.id_for_label }}" class="form-label">Contact Person</label>
{{ form.contact_person }}
{% if form.contact_person.errors %}
<div class="invalid-feedback d-block">
{{ form.contact_person.errors.0 }}
</div>
{% endif %}
</div>
<div class="col-md-6 mb-3">
<label for="{{ form.contact_title.id_for_label }}" class="form-label">Title</label>
{{ form.contact_title }}
{% if form.contact_title.errors %}
<div class="invalid-feedback d-block">
{{ form.contact_title.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="{{ form.phone.id_for_label }}" class="form-label">Phone</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-phone"></i></span>
{{ form.phone }}
</div>
{% if form.phone.errors %}
<div class="invalid-feedback d-block">
{{ form.phone.errors.0 }}
</div>
{% endif %}
</div>
<div class="col-md-6 mb-3">
<label for="{{ form.email.id_for_label }}" class="form-label">Email</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-envelope"></i></span>
{{ form.email }}
</div>
{% if form.email.errors %}
<div class="invalid-feedback d-block">
{{ form.email.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="mb-3">
<label for="{{ form.website.id_for_label }}" class="form-label">Website</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-globe"></i></span>
{{ form.website }}
</div>
{% if form.website.errors %}
<div class="invalid-feedback d-block">
{{ form.website.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
<!-- Address Information -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-map-marker-alt me-2"></i>Address Information
</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="{{ form.address.id_for_label }}" class="form-label">Street Address</label>
{{ form.address }}
{% if form.address.errors %}
<div class="invalid-feedback d-block">
{{ form.address.errors.0 }}
</div>
{% endif %}
</div>
<div class="row">
<div class="col-md-4 mb-3">
<label for="{{ form.city.id_for_label }}" class="form-label">City</label>
{{ form.city }}
{% if form.city.errors %}
<div class="invalid-feedback d-block">
{{ form.city.errors.0 }}
</div>
{% endif %}
</div>
<div class="col-md-4 mb-3">
<label for="{{ form.state.id_for_label }}" class="form-label">State/Province</label>
{{ form.state }}
{% if form.state.errors %}
<div class="invalid-feedback d-block">
{{ form.state.errors.0 }}
</div>
{% endif %}
</div>
<div class="col-md-4 mb-3">
<label for="{{ form.zip_code.id_for_label }}" class="form-label">ZIP/Postal Code</label>
{{ form.zip_code }}
{% if form.zip_code.errors %}
<div class="invalid-feedback d-block">
{{ form.zip_code.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="mb-3">
<label for="{{ form.country.id_for_label }}" class="form-label">Country</label>
{{ form.country }}
{% if form.country.errors %}
<div class="invalid-feedback d-block">
{{ form.country.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
<!-- Business Information -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-building me-2"></i>Business Information
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label for="{{ form.tax_id.id_for_label }}" class="form-label">Tax ID</label>
{{ form.tax_id }}
{% if form.tax_id.errors %}
<div class="invalid-feedback d-block">
{{ form.tax_id.errors.0 }}
</div>
{% endif %}
<div class="form-text">Tax identification number</div>
</div>
<div class="col-md-6 mb-3">
<label for="{{ form.license_number.id_for_label }}" class="form-label">License Number</label>
{{ form.license_number }}
{% if form.license_number.errors %}
<div class="invalid-feedback d-block">
{{ form.license_number.errors.0 }}
</div>
{% endif %}
<div class="form-text">Business license or registration number</div>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="{{ form.payment_terms.id_for_label }}" class="form-label">Payment Terms</label>
{{ form.payment_terms }}
{% if form.payment_terms.errors %}
<div class="invalid-feedback d-block">
{{ form.payment_terms.errors.0 }}
</div>
{% endif %}
</div>
<div class="col-md-6 mb-3">
<label for="{{ form.credit_limit.id_for_label }}" class="form-label">Credit Limit</label>
<div class="input-group">
<span class="input-group-text">$</span>
{{ form.credit_limit }}
</div>
{% if form.credit_limit.errors %}
<div class="invalid-feedback d-block">
{{ form.credit_limit.errors.0 }}
</div>
{% endif %}
<div class="form-text">Maximum credit amount allowed</div>
</div>
</div>
<div class="mb-3">
<label for="{{ form.rating.id_for_label }}" class="form-label">Rating</label>
{{ form.rating }}
{% if form.rating.errors %}
<div class="invalid-feedback d-block">
{{ form.rating.errors.0 }}
</div>
{% endif %}
<div class="form-text">Supplier performance rating (1-5 stars)</div>
</div>
</div>
</div>
<!-- Notes -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-sticky-note me-2"></i>Additional Notes
</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="{{ form.notes.id_for_label }}" class="form-label">Notes</label>
{{ form.notes }}
{% if form.notes.errors %}
<div class="invalid-feedback d-block">
{{ form.notes.errors.0 }}
</div>
{% endif %}
<div class="form-text">Additional information about the supplier</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<button type="button" class="btn btn-outline-secondary" onclick="resetForm()">
<i class="fas fa-undo me-2"></i>Reset
</button>
<button type="button" class="btn btn-outline-info" onclick="previewSupplier()">
<i class="fas fa-eye me-2"></i>Preview
</button>
</div>
<div>
<a href="{% if object %}{% url 'inventory:supplier_detail' object.pk %}{% else %}{% url 'inventory:supplier_list' %}{% endif %}"
class="btn btn-outline-secondary me-2">
<i class="fas fa-times me-2"></i>Cancel
</a>
<button type="submit" class="btn btn-primary" id="saveButton">
<i class="fas fa-save me-2"></i>{% if object %}Update Supplier{% else %}Create Supplier{% endif %}
</button>
</div>
</div>
</div>
</div>
</form>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Form Help -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-question-circle me-2"></i>Form Help
</h5>
</div>
<div class="card-body">
<div class="accordion" id="helpAccordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#basicInfo">
Basic Information
</button>
</h2>
<div id="basicInfo" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled mb-0">
<li><strong>Supplier Code:</strong> Unique identifier for internal use</li>
<li><strong>Name:</strong> Official business name</li>
<li><strong>Type:</strong> Category of products/services provided</li>
<li><strong>Status:</strong> Whether the supplier is currently active</li>
</ul>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#contactInfo">
Contact Information
</button>
</h2>
<div id="contactInfo" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled mb-0">
<li><strong>Contact Person:</strong> Primary contact at the supplier</li>
<li><strong>Phone:</strong> Primary phone number</li>
<li><strong>Email:</strong> Primary email address</li>
<li><strong>Website:</strong> Company website URL</li>
</ul>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#businessInfo">
Business Information
</button>
</h2>
<div id="businessInfo" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled mb-0">
<li><strong>Tax ID:</strong> Federal tax identification number</li>
<li><strong>License:</strong> Business license or registration</li>
<li><strong>Payment Terms:</strong> Standard payment terms</li>
<li><strong>Credit Limit:</strong> Maximum outstanding balance</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Validation Status -->
<div class="card mb-4" id="validationCard" style="display: none;">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-check-circle me-2"></i>Validation Status
</h5>
</div>
<div class="card-body">
<div id="validationResults"></div>
</div>
</div>
<!-- Quick Actions -->
{% if object %}
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-bolt me-2"></i>Quick Actions
</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<a href="{% url 'inventory:supplier_detail' object.pk %}" class="btn btn-outline-primary">
<i class="fas fa-eye me-2"></i>View Details
</a>
<a href="{% url 'inventory:purchase_order_create' %}?supplier={{ object.id }}" class="btn btn-outline-success">
<i class="fas fa-shopping-cart me-2"></i>Create Order
</a>
<button type="button" class="btn btn-outline-info" onclick="duplicateSupplier()">
<i class="fas fa-copy me-2"></i>Duplicate
</button>
<a href="{% url 'inventory:supplier_delete' object.pk %}" class="btn btn-outline-danger">
<i class="fas fa-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<script>
// Supplier form functionality
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('supplierForm');
const saveButton = document.getElementById('saveButton');
// Form validation
form.addEventListener('submit', function(e) {
if (!form.checkValidity()) {
e.preventDefault();
e.stopPropagation();
} else {
// Show loading state
saveButton.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Saving...';
saveButton.disabled = true;
}
form.classList.add('was-validated');
});
// Real-time validation
const requiredFields = form.querySelectorAll('[required]');
requiredFields.forEach(field => {
field.addEventListener('blur', validateField);
field.addEventListener('input', validateField);
});
function validateField(e) {
const field = e.target;
const isValid = field.checkValidity();
if (isValid) {
field.classList.remove('is-invalid');
field.classList.add('is-valid');
} else {
field.classList.remove('is-valid');
field.classList.add('is-invalid');
}
updateValidationStatus();
}
function updateValidationStatus() {
const validationCard = document.getElementById('validationCard');
const validationResults = document.getElementById('validationResults');
const validFields = form.querySelectorAll('.is-valid').length;
const invalidFields = form.querySelectorAll('.is-invalid').length;
const totalRequired = requiredFields.length;
if (validFields > 0 || invalidFields > 0) {
validationCard.style.display = 'block';
validationResults.innerHTML = `
<div class="d-flex justify-content-between mb-2">
<span>Valid Fields:</span>
<span class="text-success">${validFields}</span>
</div>
<div class="d-flex justify-content-between mb-2">
<span>Invalid Fields:</span>
<span class="text-danger">${invalidFields}</span>
</div>
<div class="progress" style="height: 6px;">
<div class="progress-bar bg-success" role="progressbar"
style="width: ${(validFields / totalRequired) * 100}%"></div>
</div>
`;
}
}
// Auto-generate supplier code
const nameField = document.getElementById('{{ form.name.id_for_label }}');
const codeField = document.getElementById('{{ form.supplier_code.id_for_label }}');
if (nameField && codeField && !codeField.value) {
nameField.addEventListener('input', function() {
if (!codeField.value) {
const code = this.value.toUpperCase()
.replace(/[^A-Z0-9]/g, '')
.substring(0, 10);
codeField.value = code;
}
});
}
// Phone number formatting
const phoneField = document.getElementById('{{ form.phone.id_for_label }}');
if (phoneField) {
phoneField.addEventListener('input', function() {
let value = this.value.replace(/\D/g, '');
if (value.length >= 6) {
value = value.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
} else if (value.length >= 3) {
value = value.replace(/(\d{3})(\d{0,3})/, '($1) $2');
}
this.value = value;
});
}
});
function resetForm() {
if (confirm('Are you sure you want to reset the form? All unsaved changes will be lost.')) {
document.getElementById('supplierForm').reset();
document.querySelectorAll('.is-valid, .is-invalid').forEach(field => {
field.classList.remove('is-valid', 'is-invalid');
});
document.getElementById('validationCard').style.display = 'none';
}
}
function previewSupplier() {
// Implement supplier preview functionality
alert('Preview functionality coming soon!');
}
function duplicateSupplier() {
if (confirm('Create a copy of this supplier?')) {
window.location.href = '{% url "inventory:supplier_create" %}?duplicate={{ object.pk }}';
}
}
// Auto-save functionality
let autoSaveTimeout;
document.getElementById('supplierForm').addEventListener('input', function() {
clearTimeout(autoSaveTimeout);
autoSaveTimeout = setTimeout(() => {
// Auto-save draft
console.log('Auto-saving draft...');
}, 30000); // Save after 30 seconds of inactivity
});
</script>
<style>
.form-control.is-valid,
.form-select.is-valid {
border-color: #198754;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='m2.3 6.73.94-.94 1.38 1.38 3.22-3.22.94.94-4.16 4.16z'/%3e%3c/svg%3e");
}
.form-control.is-invalid,
.form-select.is-invalid {
border-color: #dc3545;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath d='m5.8 4.6 1.4 1.4 1.4-1.4'/%3e%3c/svg%3e");
}
.accordion-button:not(.collapsed) {
background-color: #f8f9fa;
color: #0d6efd;
}
.progress {
background-color: #e9ecef;
}
@media (max-width: 768px) {
.d-flex.justify-content-between {
flex-direction: column;
gap: 1rem;
}
.btn-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.col-md-6, .col-md-4 {
margin-bottom: 1rem;
}
}
</style>
{% endblock %}