# 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'}), }