Django_Basic_Manufacturing/manufacture/views.py
2025-08-19 19:06:26 +07:00

281 lines
11 KiB
Python

from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import ListView, DetailView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib import messages
from django.http import JsonResponse
from .models import ManufacturingOrder, BillOfMaterials
from inventory.models import Product
from .forms import ManufacturingOrderForm, BillOfMaterialsForm, MultipleBillOfMaterialsForm, BOMComponentFormSet
from users.views import has_manufacturing_access
@method_decorator(login_required, name='dispatch')
class ManufactureListView(ListView):
model = ManufacturingOrder
template_name = 'manufacture/manufacture_list.html'
context_object_name = 'manufacturing_orders'
paginate_by = 20
@method_decorator(login_required, name='dispatch')
class BillOfMaterialsListView(ListView):
model = BillOfMaterials
template_name = 'manufacture/bom_list.html'
context_object_name = 'boms'
paginate_by = 20
def get_queryset(self):
queryset = super().get_queryset()
# Optionally filter by manufactured product
product_id = self.request.GET.get('product_id')
if product_id:
queryset = queryset.filter(manufactured_product_id=product_id)
return queryset
@login_required
def manufacture_create(request):
"""Create a new manufacturing order with simple input"""
if request.method == 'POST':
form = ManufacturingOrderForm(request.POST)
if form.is_valid():
manufacturing_order = form.save(commit=False)
manufacturing_order.created_by = request.user
# Generate order number if not provided
if not manufacturing_order.order_number:
# Get the next order number
last_order = ManufacturingOrder.objects.order_by('-id').first()
if last_order:
try:
last_number = int(last_order.order_number.split('-')[-1])
new_number = last_number + 1
except:
new_number = 1
else:
new_number = 1
manufacturing_order.order_number = f"MO-{new_number:06d}"
# Set status to completed by default for simplicity
manufacturing_order.status = 'completed'
manufacturing_order.save()
messages.success(request, f'Manufacturing order "{manufacturing_order.order_number}" created successfully!')
return redirect('manufacture:manufacture_detail', pk=manufacturing_order.pk)
else:
form = ManufacturingOrderForm()
return render(request, 'manufacture/manufacture_form.html', {'form': form, 'title': 'Create Manufacturing Order'})
@login_required
def manufacture_edit(request, pk):
"""Edit an existing manufacturing order"""
if not has_manufacturing_access(request.user):
messages.error(request, 'You do not have permission to edit manufacturing orders.')
return redirect('manufacture:manufacture_detail', pk=pk)
manufacturing_order = get_object_or_404(ManufacturingOrder, pk=pk)
if request.method == 'POST':
form = ManufacturingOrderForm(request.POST, instance=manufacturing_order)
if form.is_valid():
form.save()
messages.success(request, f'Manufacturing order "{manufacturing_order.order_number}" updated successfully!')
return redirect('manufacture:manufacture_detail', pk=manufacturing_order.pk)
else:
form = ManufacturingOrderForm(instance=manufacturing_order)
return render(request, 'manufacture/manufacture_form.html', {
'form': form,
'title': 'Edit Manufacturing Order',
'manufacturing_order': manufacturing_order
})
@login_required
def manufacture_delete(request, pk):
"""Delete a manufacturing order"""
if not has_manufacturing_access(request.user):
messages.error(request, 'You do not have permission to delete manufacturing orders.')
return redirect('manufacture:manufacture_list')
manufacturing_order = get_object_or_404(ManufacturingOrder, pk=pk)
if request.method == 'POST':
order_number = manufacturing_order.order_number
manufacturing_order.delete()
messages.success(request, f'Manufacturing order "{order_number}" deleted successfully!')
return redirect('manufacture:manufacture_list')
return render(request, 'manufacture/manufacture_confirm_delete.html', {'manufacturing_order': manufacturing_order})
@login_required
def bom_create(request):
"""Create a new bill of materials entry"""
if not has_manufacturing_access(request.user):
messages.error(request, 'You do not have permission to create bill of materials entries.')
return redirect('manufacture:bom_list')
if request.method == 'POST':
main_form = MultipleBillOfMaterialsForm(request.POST)
component_formset = BOMComponentFormSet(request.POST)
if main_form.is_valid() and component_formset.is_valid():
manufactured_product = main_form.cleaned_data['manufactured_product']
# Save all component entries
saved_components = []
for component_form in component_formset:
# Skip empty forms
if not component_form.cleaned_data:
continue
component = component_form.cleaned_data['component']
quantity = component_form.cleaned_data['quantity']
unit = component_form.cleaned_data['unit']
# Create BOM entry
bom = BillOfMaterials(
manufactured_product=manufactured_product,
component=component,
quantity=quantity,
unit=unit
)
bom.save()
saved_components.append(bom)
messages.success(request, f'Bill of Materials for "{manufactured_product.name}" with {len(saved_components)} components created successfully!')
return redirect('manufacture:bom_list')
else:
main_form = MultipleBillOfMaterialsForm()
component_formset = BOMComponentFormSet()
return render(request, 'manufacture/bom_form.html', {
'main_form': main_form,
'component_formset': component_formset,
'title': 'Create Bill of Materials'
})
@login_required
def bom_edit(request, pk):
"""Edit an existing bill of materials entry"""
if not has_manufacturing_access(request.user):
messages.error(request, 'You do not have permission to edit bill of materials.')
return redirect('manufacture:bom_list')
# Get the BOM entry to edit
bom = get_object_or_404(BillOfMaterials, pk=pk)
if request.method == 'POST':
main_form = MultipleBillOfMaterialsForm(request.POST)
component_formset = BOMComponentFormSet(request.POST)
if main_form.is_valid() and component_formset.is_valid():
manufactured_product = main_form.cleaned_data['manufactured_product']
# Delete existing BOM entries for this manufactured product
BillOfMaterials.objects.filter(manufactured_product=manufactured_product).delete()
# Save all component entries
saved_components = []
for component_form in component_formset:
# Skip empty forms
if not component_form.cleaned_data:
continue
component = component_form.cleaned_data['component']
quantity = component_form.cleaned_data['quantity']
unit = component_form.cleaned_data['unit']
# Create BOM entry
bom_entry = BillOfMaterials(
manufactured_product=manufactured_product,
component=component,
quantity=quantity,
unit=unit
)
bom_entry.save()
saved_components.append(bom_entry)
messages.success(request, f'Bill of Materials for "{manufactured_product.name}" with {len(saved_components)} components updated successfully!')
return redirect('manufacture:bom_list')
else:
# Pre-populate the form with existing components
main_form = MultipleBillOfMaterialsForm(initial={'manufactured_product': bom.manufactured_product})
# Get all existing components for this manufactured product
existing_components = BillOfMaterials.objects.filter(manufactured_product=bom.manufactured_product)
# Create initial data for the formset
initial_data = []
for existing_bom in existing_components:
initial_data.append({
'component': existing_bom.component,
'quantity': existing_bom.quantity,
'unit': existing_bom.unit
})
# Add extra empty forms if needed
while len(initial_data) < 1:
initial_data.append({})
component_formset = BOMComponentFormSet(initial=initial_data)
return render(request, 'manufacture/bom_form.html', {
'main_form': main_form,
'component_formset': component_formset,
'title': 'Edit Bill of Materials',
'bom': bom
})
@login_required
def bom_delete(request, pk):
"""Delete a bill of materials entry"""
if not has_manufacturing_access(request.user):
messages.error(request, 'You do not have permission to delete bill of materials entries.')
return redirect('manufacture:bom_list')
bom = get_object_or_404(BillOfMaterials, pk=pk)
if request.method == 'POST':
manufactured_product_name = bom.manufactured_product.name
bom.delete()
messages.success(request, f'Bill of Materials entry for "{manufactured_product_name}" deleted successfully!')
return redirect('manufacture:bom_list')
return render(request, 'manufacture/bom_confirm_delete.html', {'bom': bom})
@method_decorator(login_required, name='dispatch')
class ManufactureDetailView(DetailView):
model = ManufacturingOrder
template_name = 'manufacture/manufacture_detail.html'
context_object_name = 'manufacturing_order'
@method_decorator(login_required, name='dispatch')
class BillOfMaterialsDetailView(DetailView):
model = BillOfMaterials
template_name = 'manufacture/bom_detail.html'
context_object_name = 'bom'
@login_required
def get_product_info(request, product_id):
"""Return product information including unit as JSON"""
if not has_manufacturing_access(request.user):
return JsonResponse({'error': 'Permission denied'}, status=403)
try:
product = Product.objects.get(id=product_id)
return JsonResponse({
'id': product.id,
'name': product.name,
'unit': product.unit,
'unit_display': product.get_unit_display()
})
except Product.DoesNotExist:
return JsonResponse({'error': 'Product not found'}, status=404)