diff --git a/cmp/forms.py b/cmp/forms.py index c5a06a9..7e75b1d 100644 --- a/cmp/forms.py +++ b/cmp/forms.py @@ -19,22 +19,37 @@ from django.forms import inlineformset_factory from crispy_forms.helper import FormHelper -from crispy_forms.layout import Layout, Field, Div, HTML -from crispy_forms.bootstrap import Accordion, AccordionGroup +from crispy_forms.layout import Layout, Field +from crispy_forms.bootstrap import Accordion, AccordionGroup, TabHolder, Tab + +# First define the formset form +class SoldierImprisonmentForm(forms.ModelForm): + class Meta: + model = SoldierImprisonment + fields = ['pow_camp', 'pow_number', 'date_from', 'date_to', 'notes'] + widgets = { + 'date_from': forms.DateInput( + attrs={ + 'type': 'date', + 'class': 'form-control' + } + ), + 'date_to': forms.DateInput( + attrs={ + 'type': 'date', + 'class': 'form-control' + } + ) + } -# First, create a helper class for the formset class SoldierImprisonmentFormSetHelper(FormHelper): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.form_tag = False - # Check if there's any data in the formset + # Default to collapsed has_data = False - if hasattr(self, 'formset'): - has_data = any(not form.empty_permitted or form.initial for form in self.formset) - - # Set title based on whether there's data - title = 'Prisoner of War Details' if has_data else 'Prisoner of War Details (None Recorded)' + title = 'Prisoner of War Details (None Recorded)' self.layout = Layout( Accordion( @@ -45,24 +60,37 @@ def __init__(self, *args, **kwargs): 'date_from', 'date_to', 'notes', - active=has_data, # Only active if there's data - css_class='bg-light' + active=has_data, # Collapsed by default + css_class='bg-info bg-opacity-25 border rounded p-3' ), css_id="imprisonment-details-accordion" ) ) -# Then create the formset with the helper + def update_title(self): + """Update the title based on formset data""" + if hasattr(self, 'formset') and self.formset.initial_forms: + has_data = any(form.initial for form in self.formset.initial_forms) + title = 'Prisoner of War Details' if has_data else 'Prisoner of War Details (None Recorded)' + self.layout[0][0].name = title + self.layout[0][0].active = has_data + +# Create the formset SoldierImprisonmentInlineFormSet = inlineformset_factory( Soldier, SoldierImprisonment, - fields=['pow_camp', 'pow_number', 'date_from', 'date_to', 'notes'], + form=SoldierImprisonmentForm, extra=1, can_delete=True ) # Add the helper to the formset -SoldierImprisonmentInlineFormSet.helper = SoldierImprisonmentFormSetHelper() +class SoldierImprisonmentFormSetWithHelper(SoldierImprisonmentInlineFormSet): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = SoldierImprisonmentFormSetHelper() + self.helper.formset = self + self.helper.update_title() class CustomUserCreationForm(UserCreationForm): @@ -217,33 +245,23 @@ class editSoldierDeathForm(forms.ModelForm): class Meta: model = SoldierDeath fields = ['date', 'company', 'cemetery', 'cwgc_id', 'image'] + widgets = { + 'date': forms.DateInput( + attrs={ + 'type': 'date', + 'class': 'form-control' + } + ) + } + labels = { + 'image': 'Grave Photograph' # Updated label + } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.helper = FormHelper() - - # Determine header class and active state based on whether form has data - header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue' - is_active = bool(self.instance and self.instance.pk) - - # Set title based on whether there's data - title = 'Death Details' if self.instance and self.instance.pk else 'Death Details (None Recorded)' - - self.helper.layout = Layout( - Accordion( - AccordionGroup( - title, - 'date', - 'company', - 'cemetery', - 'cwgc_id', - 'image', - active=is_active, - button_class=header_class - ), - css_id="death-details-accordion" - ) - ) + self.helper = SoldierDeathFormHelper() + self.helper.form = self + self.helper.update_title() class editSoldierForm(forms.ModelForm): @@ -251,6 +269,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.label_class = 'form-label' + self.fields['provost_officer'].disabled = True # Determine header class and active state based on whether form has data header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue' @@ -342,6 +361,7 @@ class SoldierForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() + # Determine header class and active state based on whether form has data header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue' @@ -352,7 +372,7 @@ def __init__(self, *args, **kwargs): Field('initials'), Field('army_number'), Field('rank'), - Field('provost_officer'), + #Field('provost_officer'), Field('notes'), Accordion( AccordionGroup( @@ -375,18 +395,27 @@ class Meta: fields = ['surname', 'initials', 'army_number', 'rank', 'provost_officer', 'notes'] +class SoldierDecorationForm(forms.ModelForm): + class Meta: + model = SoldierDecoration + fields = ['decoration', 'gazette_issue', 'gazette_page', 'gazette_date', 'theatre', 'country', 'citation', 'notes'] + widgets = { + 'gazette_date': forms.DateInput( + attrs={ + 'type': 'date', + 'class': 'form-control' + } + ) + } + class SoldierDecorationFormSetHelper(FormHelper): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.form_tag = False - # Check if there's any data in the formset + # Default to collapsed has_data = False - if hasattr(self, 'formset'): - has_data = any(not form.empty_permitted or form.initial for form in self.formset) - - # Set title based on whether there's data - title = 'Decoration Details' if has_data else 'Decoration Details (None Recorded)' + title = 'Decoration Details (None Recorded)' self.layout = Layout( Accordion( @@ -400,23 +429,61 @@ def __init__(self, *args, **kwargs): 'country', 'citation', 'notes', - active=has_data, # Only active if there's data - css_class='bg-light' + active=has_data, + css_class='bg-info bg-opacity-25 border rounded p-3' ), css_id="decoration-details-accordion" ) ) -# Create the formset with the helper + def update_title(self): + if hasattr(self, 'formset') and self.formset.initial_forms: + has_data = any(form.initial for form in self.formset.initial_forms) + title = 'Decoration Details' if has_data else 'Decoration Details (None Recorded)' + self.layout[0][0].name = title + self.layout[0][0].active = has_data + +# Create the formset SoldierDecorationInlineFormSet = inlineformset_factory( Soldier, SoldierDecoration, - fields=['decoration', 'gazette_issue', 'gazette_page', 'gazette_date', 'theatre', 'country', 'citation', 'notes'], + form=SoldierDecorationForm, extra=1, can_delete=True ) -# Add the helper to the formset -SoldierDecorationInlineFormSet.helper = SoldierDecorationFormSetHelper() + +class SoldierDeathFormHelper(FormHelper): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.form_tag = False + + # Default to collapsed + has_data = False + title = 'Death Details (None Recorded)' + + self.layout = Layout( + Accordion( + AccordionGroup( + title, + 'date', + 'company', + 'cemetery', + 'cwgc_id', + 'image', + active=has_data, # Collapsed by default + css_class='bg-info bg-opacity-25 border rounded p-3' + ), + css_id="death-details-accordion" + ) + ) + + def update_title(self): + """Update the title based on form data""" + if hasattr(self, 'form') and self.form.initial: + has_data = any(self.form.initial.values()) + title = 'Death Details' if has_data else 'Death Details (None Recorded)' + self.layout[0][0].name = title + self.layout[0][0].active = has_data diff --git a/cmp/urls.py b/cmp/urls.py index e674dc6..ccae423 100644 --- a/cmp/urls.py +++ b/cmp/urls.py @@ -88,7 +88,7 @@ # Soldier management path("mgmt/soldiers/search/", views.search_soldiers, name='search-soldiers'), path("mgmt/soldiers/edit//", views.edit_soldier, name='edit-soldier'), - path("mgmt/soldiers/edit/", views.edit_soldier, name='edit-soldier'), + path("mgmt/soldiers/edit/", views.edit_soldier, name='create-soldier'), path("mgmt/soldiers/delete//", views.delete_soldier, name='delete-soldier'), path("mgmt/soldiers//", views.detail_soldiers, name='soldier-detail'), diff --git a/cmp/views.py b/cmp/views.py index 9af4d5e..7358c9d 100644 --- a/cmp/views.py +++ b/cmp/views.py @@ -38,9 +38,14 @@ from .models import SoldierImprisonment -from .forms import editSoldierForm, editSoldierDeathForm, SoldierImprisonmentInlineFormSet +from .forms import ( + editSoldierForm, editSoldierDeathForm, + SoldierImprisonmentFormSetWithHelper, + SoldierDecorationInlineFormSet, +) from .forms import SoldierDecorationInlineFormSet from .forms import ProvostOfficerForm, ProvostAppointmentForm +from .forms import SoldierImprisonmentFormSetHelper, SoldierDecorationFormSetHelper @@ -441,28 +446,93 @@ def soldier_detail(request, soldier_id): return render(request, 'cmp/soldier.html', {'soldier': soldier}) -def edit_soldier(request, id): - soldier = get_object_or_404(Soldier, pk=id) +def edit_soldier(request, id=None): + print("\n=== Starting View ===") + print(f"Method: {request.method}") + print(f"ID: {id}") + + if id: + soldier = get_object_or_404(Soldier, pk=id) + print(f"Editing existing soldier: {soldier}") + else: + soldier = None + print("Creating new soldier") + if request.method == 'POST': - form = editSoldierForm(request.POST, instance=soldier) - death_form = editSoldierDeathForm(request.POST, request.FILES, instance=getattr(soldier, 'soldierdeath', None)) - imprisonment_formset = SoldierImprisonmentInlineFormSet(request.POST, instance=soldier, prefix='imprisonment') - decoration_formset = SoldierDecorationInlineFormSet(request.POST, instance=soldier, prefix='decoration') + print("\n=== Processing POST ===") + print(f"POST data: {request.POST}") + print(f"FILES data: {request.FILES}") - if form.is_valid() and death_form.is_valid() and imprisonment_formset.is_valid() and decoration_formset.is_valid(): - form.save() - if death_form.has_changed(): - death_form.save() - imprisonment_formset.save() - decoration_formset.save() - messages.success(request, f'Soldier "{soldier.surname}, {soldier.initials}" successfully updated!') - return redirect('search-soldiers') + try: + form = editSoldierForm(request.POST, instance=soldier) + death_form = editSoldierDeathForm(request.POST, request.FILES, instance=getattr(soldier, 'soldierdeath', None)) + imprisonment_formset = SoldierImprisonmentFormSetWithHelper(request.POST, instance=soldier, prefix='imprisonment') + decoration_formset = SoldierDecorationInlineFormSet(request.POST, instance=soldier, prefix='decoration') + + print("=== Form Validation ===") + print(f"Main form bound: {form.is_bound}") + print(f"Death form bound: {death_form.is_bound}") + print(f"Imprisonment formset bound: {imprisonment_formset.is_bound}") + print(f"Decoration formset bound: {decoration_formset.is_bound}") + + form_valid = form.is_valid() + death_form_valid = death_form.is_valid() + imprisonment_formset_valid = imprisonment_formset.is_valid() + decoration_formset_valid = decoration_formset.is_valid() + + print(f"Main form valid: {form_valid}") + print(f"Death form valid: {death_form_valid}") + print(f"Imprisonment formset valid: {imprisonment_formset_valid}") + print(f"Decoration formset valid: {decoration_formset_valid}") + + if all([form_valid, death_form_valid, imprisonment_formset_valid, decoration_formset_valid]): + print("=== Saving Forms ===") + soldier = form.save() + print(f"Main form saved: {soldier}") + + if death_form.has_changed(): + print("Death form has changes:", death_form.changed_data) + death_instance = death_form.save(commit=False) + death_instance.soldier = soldier + death_instance.save() + print("Death form saved") + + # Check if any form in the formset has changes + if any(form.has_changed() for form in imprisonment_formset): + print("Imprisonment formset has changes") + imprisonment_formset.instance = soldier + imprisonment_formset.save() + print("Imprisonment formset saved") + + if any(form.has_changed() for form in decoration_formset): + print("Decoration formset has changes") + decoration_formset.instance = soldier + decoration_formset.save() + print("Decoration formset saved") + + messages.success(request, f'Soldier "{soldier.surname}, {soldier.initials}" successfully {"updated" if id else "created"}!') + return redirect('search-soldiers') + else: + if not form_valid: + print(f"Main form errors: {form.errors}") + if not death_form_valid: + print(f"Death form errors: {death_form.errors}") + if not imprisonment_formset_valid: + print(f"Imprisonment formset errors: {imprisonment_formset.errors}") + if not decoration_formset_valid: + print(f"Decoration formset errors: {decoration_formset.errors}") + messages.error(request, 'Please correct the errors below.') + except Exception as e: + print(f"Exception occurred: {str(e)}") + messages.error(request, f'Error: {str(e)}') else: form = editSoldierForm(instance=soldier) death_form = editSoldierDeathForm(instance=getattr(soldier, 'soldierdeath', None)) - imprisonment_formset = SoldierImprisonmentInlineFormSet(instance=soldier, prefix='imprisonment') + imprisonment_formset = SoldierImprisonmentFormSetWithHelper(instance=soldier, prefix='imprisonment') + imprisonment_formset.helper = SoldierImprisonmentFormSetHelper() decoration_formset = SoldierDecorationInlineFormSet(instance=soldier, prefix='decoration') - + decoration_formset.helper = SoldierDecorationFormSetHelper() + return render(request, 'cmp/edit-soldiers.html', { 'form': form, 'death_form': death_form, diff --git a/templates/cmp/edit-companies.html b/templates/cmp/edit-companies.html index 4edfe88..c868418 100644 --- a/templates/cmp/edit-companies.html +++ b/templates/cmp/edit-companies.html @@ -1,20 +1,22 @@ {% extends "base.html" %} -{% load static crispy_forms_tags %} -{% block title %}Companies Form{% endblock %} -{% block content %} - -
-

Edit Companies

+{% load static %} +{% load crispy_forms_tags %} -
-
- {% csrf_token %} - {{ form.management_form }} - {{ form.errors }} - {{form | crispy}} - -
-
+{% block title %}{% if company %}Edit{% else %}Add{% endif %} Company{% endblock %} -{% endblock %} -
\ No newline at end of file +{% block content %} +
+

{% if company %}Edit{% else %}Add{% endif %} Company

+
+ {% csrf_token %} + {{ form|crispy }} + + {% if company %} + + {% endif %} +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/cmp/edit-soldiers.html b/templates/cmp/edit-soldiers.html index f4da340..5e13d71 100644 --- a/templates/cmp/edit-soldiers.html +++ b/templates/cmp/edit-soldiers.html @@ -4,20 +4,29 @@ {% block content %}
+ {% if messages %} +
+ {% for message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+ {% endif %} +

{% if soldier %}Edit{% else %}Add{% endif %} Soldier

-
+ {% csrf_token %} {{ form|crispy }} - - {{ decoration_formset.management_form }} - {% crispy decoration_formset decoration_formset.helper %} - {% crispy death_form %} + {% crispy death_form death_form.helper %} {{ imprisonment_formset.management_form }} {% crispy imprisonment_formset imprisonment_formset.helper %} + {{ decoration_formset.management_form }} + {% crispy decoration_formset decoration_formset.helper %}
diff --git a/templates/cmp/search-soldiers.html b/templates/cmp/search-soldiers.html index ec4b4b8..228b8e6 100644 --- a/templates/cmp/search-soldiers.html +++ b/templates/cmp/search-soldiers.html @@ -15,7 +15,7 @@

Search/Edit/Add/Delete Soldiers

- + Add New Soldier
@@ -41,7 +41,7 @@

Search/Edit/Add/Delete Soldiers

{% for soldier in page_obj %} - + {{ soldier.surname }} {{ soldier.initials }} {{ soldier.army_number }}