cmc-sales/cmc-django/cmcsales/cmc/forms.py

396 lines
14 KiB
Python
Raw Normal View History

# forms.py
from django import forms
from django.contrib.auth import get_user_model # To reference the User model
from .models import (
Currency, Country, State, Status, CustomerCategory, ContactCategory,
Industry, ProductCategory, FreightForwarder, FreightService,
Customer, Address, Principle, PrincipleAddress, Contact,
Product, ProductAttachment, ProductOptionsCategory, ProductOption,
Document, DocPage, Attachment, DocumentAttachment,
Enquiry, EnquiryEmailQueue, EnquiryFile, Job, LineItem, Costing,
Quote, Invoice, PurchaseOrder, OrderAcknowledgement, PackingList,
Email, EmailRecipient, EmailAttachment,
Shipment, Box, ShipmentInvoice,
# Import other models if forms are needed for them
)
# Get the custom User model if you have one, otherwise the default User
User = get_user_model()
# --- Base Model Forms ---
class CurrencyForm(forms.ModelForm):
class Meta:
model = Currency
fields = ['name', 'code', 'symbol']
class CountryForm(forms.ModelForm):
class Meta:
model = Country
fields = ['name', 'currency']
class StateForm(forms.ModelForm):
class Meta:
model = State
fields = ['name', 'shortform']
class StatusForm(forms.ModelForm):
class Meta:
model = Status
fields = ['name', 'css_class']
class CustomerCategoryForm(forms.ModelForm):
class Meta:
model = CustomerCategory
fields = ['name']
class ContactCategoryForm(forms.ModelForm):
class Meta:
model = ContactCategory
fields = ['name']
class IndustryForm(forms.ModelForm):
class Meta:
model = Industry
fields = ['name', 'parent']
class ProductCategoryForm(forms.ModelForm):
class Meta:
model = ProductCategory
fields = ['name']
class FreightForwarderForm(forms.ModelForm):
class Meta:
model = FreightForwarder
fields = ['name']
class FreightServiceForm(forms.ModelForm):
class Meta:
model = FreightService
fields = ['name', 'freight_forwarder']
# --- Core Model Forms ---
class CustomerForm(forms.ModelForm):
industries = forms.ModelMultipleChoiceField(
queryset=Industry.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=False
)
class Meta:
model = Customer
fields = [
'name', 'abn', 'customer_category', 'country', 'industries'
]
widgets = {
'abn': forms.TextInput(attrs={'placeholder': 'Enter 11 digit ABN'}),
}
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = [
'customer', 'address_line_1', 'address_line_2', 'city',
'postcode', 'state', 'country', 'type'
]
# You might want to filter 'customer', 'state', 'country' dropdowns
# dynamically in the view based on context.
class PrincipleForm(forms.ModelForm):
class Meta:
model = Principle
fields = ['name', 'city', 'country', 'currency']
class PrincipleAddressForm(forms.ModelForm):
class Meta:
model = PrincipleAddress
fields = [
'principle', 'address_line_1', 'address_line_2', 'city',
'postcode', 'country', 'type'
]
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = [
'first_name', 'last_name', 'email', 'job_title',
'customer', 'contact_category'
]
# Consider making principle/customer mutually exclusive or adding validation
# depending on business logic.
# --- Product Related Forms ---
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = [
'principle', 'product_category', 'name', 'description', 'model_number'
]
widgets = {
'description': forms.Textarea(attrs={'rows': 3}),
}
class ProductAttachmentForm(forms.ModelForm):
class Meta:
model = ProductAttachment
fields = ['product', 'file', 'description']
widgets = {
'description': forms.TextInput(attrs={'placeholder': 'Optional description'}),
}
class ProductOptionsCategoryForm(forms.ModelForm):
class Meta:
model = ProductOptionsCategory
fields = ['product', 'name', 'location', 'exclusive']
class ProductOptionForm(forms.ModelForm):
class Meta:
model = ProductOption
fields = [
'product_options_category', 'name', 'value',
'price_adjustment', 'is_default'
]
# --- Document / Enquiry / Job / Order Flow Forms ---
# Note: Document model is abstract-like. Forms usually handle specific types (Quote, Invoice etc.)
class EnquiryForm(forms.ModelForm):
# Custom fields or overrides can go here
send_enquiry_email = forms.BooleanField(
required=False,
initial=True, # Default to sending email? Adjust as needed.
label="Send Confirmation Email to Contact?"
)
class Meta:
model = Enquiry
fields = [
# 'title' is often auto-generated, exclude it from user input forms
'user', 'customer', 'contact', 'state', 'country', 'principle',
'status', 'billing_address', 'shipping_address', 'gst',
'comments',
# Add the custom field
'send_enquiry_email'
]
widgets = {
'description': forms.Textarea(attrs={'rows': 4}),
# Consider using ModelChoiceFields with filtered querysets for addresses
# based on the selected customer in the view.
'billing_address': forms.Select(),
'shipping_address': forms.Select(),
}
def __init__(self, *args, **kwargs):
# Optionally filter choices based on passed arguments (e.g., customer)
customer = kwargs.pop('customer', None)
super().__init__(*args, **kwargs)
# Filter user choices to only active staff users (example)
self.fields['user'].queryset = User.objects.filter(is_active=True, is_staff=True) # Adjust filter as needed
# Filter contact choices based on the customer (if provided)
if customer:
self.fields['contact'].queryset = Contact.objects.filter(customer=customer)
self.fields['billing_address'].queryset = Address.objects.filter(customer=customer, type__in=['billing', 'physical']) # Example filter
self.fields['shipping_address'].queryset = Address.objects.filter(customer=customer, type__in=['shipping', 'physical'])
elif self.instance and self.instance.pk and self.instance.customer:
# If editing an existing instance, filter based on its customer
customer = self.instance.customer
self.fields['contact'].queryset = Contact.objects.filter(customer=customer)
self.fields['billing_address'].queryset = Address.objects.filter(customer=customer, type__in=['billing', 'physical'])
self.fields['shipping_address'].queryset = Address.objects.filter(customer=customer, type__in=['shipping', 'physical'])
else:
# No customer context, clear or disable these fields initially
self.fields['contact'].queryset = Contact.objects.none()
self.fields['billing_address'].queryset = Address.objects.none()
self.fields['shipping_address'].queryset = Address.objects.none()
# You might want to filter 'state' based on 'country' using JavaScript
# or libraries like django-smart-selects.
class EnquiryStatusForm(forms.Form):
"""Simple form for AJAX status updates."""
enquiry_id = forms.IntegerField(widget=forms.HiddenInput())
status_id = forms.ModelChoiceField(queryset=Status.objects.all(), empty_label=None)
class EnquirySearchForm(forms.Form):
"""Form for the search functionality."""
search_string = forms.CharField(
label="Search Enquiries, Customers, Contacts, Jobs",
max_length=100,
widget=forms.TextInput(attrs={'placeholder': 'Enter name, enquiry #, job #, etc.'})
)
class EnquiryFileForm(forms.ModelForm):
class Meta:
model = EnquiryFile
fields = ['enquiry', 'file', 'description']
class JobForm(forms.ModelForm):
class Meta:
model = Job
fields = [
# 'title' might be auto-generated
'enquiry', 'customer', 'contact', 'state', 'currency',
'customer_order_number', 'date_order_received',
'all_sent', 'all_paid', 'comments'
# Add other fields like freight/sale/shipment categories if needed
]
widgets = {
'comments': forms.Textarea(attrs={'rows': 3}),
'date_order_received': forms.DateInput(attrs={'type': 'date'}),
}
# Similar filtering logic for contact based on customer might be needed here
class LineItemForm(forms.ModelForm):
class Meta:
model = LineItem
fields = [
'document', 'product', 'item_number', 'description',
'quantity', 'unit_price'
]
widgets = {
'description': forms.Textarea(attrs={'rows': 2}),
}
# Note: 'document' and 'item_number' are often set programmatically
# when using formsets.
class CostingForm(forms.ModelForm):
class Meta:
model = Costing
fields = [
'line_item', 'product', 'purchase_currency', 'sale_currency',
'purchase_price', 'sale_price', 'exchange_rate'
# Add other costing fields
]
# Note: 'line_item' and 'product' often set programmatically.
class QuoteForm(forms.ModelForm):
class Meta:
model = Quote
fields = [
# 'document' is the PK, usually not directly editable here
'enquiry', 'currency', 'title', 'revision', 'delivery_time',
'payment_terms', 'days_valid', 'issue_date'
]
widgets = {
'issue_date': forms.DateInput(attrs={'type': 'date'}),
}
class InvoiceForm(forms.ModelForm):
class Meta:
model = Invoice
fields = [
# 'document' is PK
'enquiry', 'job', 'customer', 'currency', 'title',
'issue_date', 'due_date', 'paid', 'date_paid'
]
widgets = {
'issue_date': forms.DateInput(attrs={'type': 'date'}),
'due_date': forms.DateInput(attrs={'type': 'date'}),
'date_paid': forms.DateInput(attrs={'type': 'date'}),
}
class PurchaseOrderForm(forms.ModelForm):
jobs = forms.ModelMultipleChoiceField(
queryset=Job.objects.all(), # Filter as needed in view
widget=forms.CheckboxSelectMultiple,
required=False
)
class Meta:
model = PurchaseOrder
fields = [
# 'document' is PK
'principle', 'currency', 'title', 'issue_date', 'jobs'
]
widgets = {
'issue_date': forms.DateInput(attrs={'type': 'date'}),
}
class OrderAcknowledgementForm(forms.ModelForm):
class Meta:
model = OrderAcknowledgement
fields = [
# 'document' is PK
'enquiry', 'job', 'currency', 'title', 'revision',
'delivery_time', 'payment_terms', 'issue_date'
]
widgets = {
'issue_date': forms.DateInput(attrs={'type': 'date'}),
}
class PackingListForm(forms.ModelForm):
class Meta:
model = PackingList
fields = [
# 'document' is PK
'enquiry', 'job', 'customer', 'currency', 'title', 'issue_date'
]
widgets = {
'issue_date': forms.DateInput(attrs={'type': 'date'}),
}
# --- Email Related Forms (Less common for direct user input) ---
# Forms for Email, EmailRecipient, EmailAttachment are less likely needed
# as these are often populated programmatically (e.g., by an email processing script).
# If you need forms for manual linking or editing, create them similarly.
# --- Shipment Related Forms ---
class ShipmentForm(forms.ModelForm):
jobs = forms.ModelMultipleChoiceField(
queryset=Job.objects.all(), # Filter as needed
widget=forms.CheckboxSelectMultiple,
required=False
)
principles = forms.ModelMultipleChoiceField(
queryset=Principle.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=False
)
purchase_orders = forms.ModelMultipleChoiceField(
queryset=PurchaseOrder.objects.all(), # Filter as needed
widget=forms.CheckboxSelectMultiple,
required=False
)
class Meta:
model = Shipment
fields = [
'title', 'freight_forwarder', 'freight_service', 'user',
'customer', 'address', 'airway_bill', 'ship_date',
'expected_delivery_date', 'actual_delivery_date',
'jobs', 'principles', 'purchase_orders'
]
widgets = {
'ship_date': forms.DateInput(attrs={'type': 'date'}),
'expected_delivery_date': forms.DateInput(attrs={'type': 'date'}),
'actual_delivery_date': forms.DateInput(attrs={'type': 'date'}),
}
# Add filtering for 'address' based on 'customer' in the view/init
class BoxForm(forms.ModelForm):
class Meta:
model = Box
fields = [
'shipment', 'box_number', 'length', 'width', 'height', 'weight'
]
# 'shipment' and 'box_number' often set programmatically in formsets
class ShipmentInvoiceForm(forms.ModelForm):
class Meta:
model = ShipmentInvoice
fields = [
'shipment', 'principle', 'freight_forwarder', 'currency',
'invoice_number', 'issue_date', 'amount', 'description'
]
widgets = {
'issue_date': forms.DateInput(attrs={'type': 'date'}),
'description': forms.TextInput(attrs={'placeholder': 'Optional description'}),
}