213 lines
11 KiB
HTML
213 lines
11 KiB
HTML
{% extends "module_base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ module_title }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title mb-0">
|
|
<i class="fas fa-industry me-2"></i>{{ module_title }}
|
|
</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post" class="needs-validation" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<!-- MO Details -->
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.mo_number.id_for_label }}" class="form-label">MO Number</label>
|
|
{{ form.mo_number }}
|
|
{% if form.mo_number.errors %}
|
|
<div class="invalid-feedback">
|
|
{% for error in form.mo_number.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.bom.id_for_label }}" class="form-label">Bill of Material</label>
|
|
{{ form.bom }}
|
|
{% if form.bom.errors %}
|
|
<div class="invalid-feedback">
|
|
{% for error in form.bom.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label for="{{ form.quantity_to_produce.id_for_label }}" class="form-label">Quantity to Produce</label>
|
|
{{ form.quantity_to_produce }}
|
|
{% if form.quantity_to_produce.errors %}
|
|
<div class="invalid-feedback">
|
|
{% for error in form.quantity_to_produce.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label for="{{ form.scheduled_start_date.id_for_label }}" class="form-label">Scheduled Start Date</label>
|
|
{{ form.scheduled_start_date }}
|
|
{% if form.scheduled_start_date.errors %}
|
|
<div class="invalid-feedback">
|
|
{% for error in form.scheduled_start_date.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label for="{{ form.scheduled_end_date.id_for_label }}" class="form-label">Scheduled End Date</label>
|
|
{{ form.scheduled_end_date }}
|
|
{% if form.scheduled_end_date.errors %}
|
|
<div class="invalid-feedback">
|
|
{% for error in form.scheduled_end_date.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- MO Components Formset -->
|
|
<div class="card mt-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Required Components</h5>
|
|
<small class="text-muted">Components will be automatically populated from the selected BOM</small>
|
|
</div>
|
|
<div class="card-body">
|
|
{{ formset.management_form }}
|
|
|
|
<div id="mo-components">
|
|
{% for form in formset %}
|
|
<div class="mo-component mb-3 p-3 border rounded">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label class="form-label">Component</label>
|
|
{{ form.component }}
|
|
{% if form.component.errors %}
|
|
<div class="invalid-feedback">
|
|
{% for error in form.component.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Required Quantity</label>
|
|
{{ form.required_quantity }}
|
|
{% if form.required_quantity.errors %}
|
|
<div class="invalid-feedback">
|
|
{% for error in form.required_quantity.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label"> </label>
|
|
<button type="button" class="btn btn-danger btn-sm remove-component">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{{ form.id }}
|
|
{% if form.DELETE %}
|
|
{{ form.DELETE }}
|
|
{% endif %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<button type="button" class="btn btn-success btn-sm" id="add-component">
|
|
<i class="fas fa-plus me-1"></i>Add Component
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="mt-4">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save me-2"></i>Save Manufacturing Order
|
|
</button>
|
|
<a href="{% url 'manufacturing:mo_list' %}" class="btn btn-secondary ms-2">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Auto-populate components when BOM changes
|
|
const bomSelect = document.getElementById('{{ form.bom.id_for_label }}');
|
|
const quantityInput = document.getElementById('{{ form.quantity_to_produce.id_for_label }}');
|
|
|
|
function populateComponents() {
|
|
if (bomSelect.value && quantityInput.value) {
|
|
// This would typically make an AJAX call to get BOM components
|
|
// For now, we'll rely on the formset being populated server-side
|
|
console.log('BOM and quantity selected - components should be populated');
|
|
}
|
|
}
|
|
|
|
if (bomSelect) {
|
|
bomSelect.addEventListener('change', populateComponents);
|
|
}
|
|
if (quantityInput) {
|
|
quantityInput.addEventListener('change', populateComponents);
|
|
}
|
|
|
|
// Add new MO component
|
|
document.getElementById('add-component').addEventListener('click', function() {
|
|
const container = document.getElementById('mo-components');
|
|
const totalForms = document.getElementById('id_mocomponent_set-TOTAL_FORMS');
|
|
const formNum = parseInt(totalForms.value);
|
|
|
|
// Create new form
|
|
const newForm = document.querySelector('.mo-component').cloneNode(true);
|
|
|
|
// Clear values
|
|
const inputs = newForm.querySelectorAll('input, select');
|
|
inputs.forEach(input => {
|
|
if (input.type === 'checkbox') {
|
|
input.checked = false;
|
|
} else {
|
|
input.value = '';
|
|
}
|
|
});
|
|
|
|
// Update form indices
|
|
const regex = new RegExp(`mocomponent_set-(\\d+)-`, 'g');
|
|
newForm.innerHTML = newForm.innerHTML.replace(regex, `mocomponent_set-${formNum}-`);
|
|
|
|
container.appendChild(newForm);
|
|
totalForms.value = formNum + 1;
|
|
});
|
|
|
|
// Remove MO component
|
|
document.addEventListener('click', function(e) {
|
|
if (e.target.classList.contains('remove-component') || e.target.closest('.remove-component')) {
|
|
const component = e.target.closest('.mo-component');
|
|
const deleteCheckbox = component.querySelector('input[type="checkbox"][name$="-DELETE"]');
|
|
if (deleteCheckbox) {
|
|
deleteCheckbox.checked = true;
|
|
component.style.display = 'none';
|
|
} else {
|
|
component.remove();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %} |