• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gm3dmo / cmp / 12535808311

29 Dec 2024 01:24PM UTC coverage: 59.79% (-4.1%) from 63.889%
12535808311

push

github

web-flow
Merge pull request #285 from gm3dmo/saves

Get Saves working

24 of 120 new or added lines in 2 files covered. (20.0%)

10 existing lines in 2 files now uncovered.

742 of 1241 relevant lines covered (59.79%)

1.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.72
/cmp/forms.py
1
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
2✔
2

3
from django import forms
2✔
4

5
from .models import CustomUser
2✔
6

7
from .models import Country
2✔
8
from .models import Rank
2✔
9
from .models import Cemetery
2✔
10
from .models import PowCamp
2✔
11
from .models import Soldier
2✔
12
from .models import SoldierDeath
2✔
13
from .models import SoldierImprisonment
2✔
14
from .models import SoldierDecoration
2✔
15
from .models import Company
2✔
16
from .models import Decoration
2✔
17
from .models import Acknowledgement
2✔
18
from .models import ProvostAppointment
2✔
19
from django.forms import inlineformset_factory
2✔
20

21
from crispy_forms.helper import FormHelper
2✔
22
from crispy_forms.layout import Layout, Field
2✔
23
from crispy_forms.bootstrap import Accordion, AccordionGroup, TabHolder, Tab
2✔
24

25
# First define the formset form
26
class SoldierImprisonmentForm(forms.ModelForm):
2✔
27
    class Meta:
2✔
28
        model = SoldierImprisonment
2✔
29
        fields = ['pow_camp', 'pow_number', 'date_from', 'date_to', 'notes']
2✔
30
        widgets = {
2✔
31
            'date_from': forms.DateInput(
32
                attrs={
33
                    'type': 'date',
34
                    'class': 'form-control'
35
                }
36
            ),
37
            'date_to': forms.DateInput(
38
                attrs={
39
                    'type': 'date',
40
                    'class': 'form-control'
41
                }
42
            )
43
        }
44

45
class SoldierImprisonmentFormSetHelper(FormHelper):
2✔
46
    def __init__(self, *args, **kwargs):
2✔
UNCOV
47
        super().__init__(*args, **kwargs)
×
UNCOV
48
        self.form_tag = False
×
49
        
50
        # Default to collapsed
UNCOV
51
        has_data = False
×
NEW
52
        title = 'Prisoner of War Details (None Recorded)'
×
53
        
UNCOV
54
        self.layout = Layout(
×
55
            Accordion(
56
                AccordionGroup(
57
                    title,
58
                    'pow_camp',
59
                    'pow_number',
60
                    'date_from',
61
                    'date_to',
62
                    'notes',
63
                    active=has_data,  # Collapsed by default
64
                    css_class='bg-info bg-opacity-25 border rounded p-3'
65
                ),
66
                css_id="imprisonment-details-accordion"
67
            )
68
        )
69

70
    def update_title(self):
2✔
71
        """Update the title based on formset data"""
NEW
72
        if hasattr(self, 'formset') and self.formset.initial_forms:
×
NEW
73
            has_data = any(form.initial for form in self.formset.initial_forms)
×
NEW
74
            title = 'Prisoner of War Details' if has_data else 'Prisoner of War Details (None Recorded)'
×
NEW
75
            self.layout[0][0].name = title
×
NEW
76
            self.layout[0][0].active = has_data
×
77

78
# Create the formset
79
SoldierImprisonmentInlineFormSet = inlineformset_factory(
2✔
80
    Soldier,
81
    SoldierImprisonment,
82
    form=SoldierImprisonmentForm,
83
    extra=1,
84
    can_delete=True
85
)
86

87
# Add the helper to the formset
88
class SoldierImprisonmentFormSetWithHelper(SoldierImprisonmentInlineFormSet):
2✔
89
    def __init__(self, *args, **kwargs):
2✔
NEW
90
        super().__init__(*args, **kwargs)
×
NEW
91
        self.helper = SoldierImprisonmentFormSetHelper()
×
NEW
92
        self.helper.formset = self
×
NEW
93
        self.helper.update_title()
×
94

95

96
class CustomUserCreationForm(UserCreationForm):
2✔
97
    class Meta:
2✔
98
        model = CustomUser
2✔
99
        fields = ("email",)
2✔
100

101

102
class CustomUserChangeForm(UserChangeForm):
2✔
103
    class Meta:
2✔
104
        model = CustomUser
2✔
105
        fields = ("email",)
2✔
106

107

108
class editPowCampForm(forms.ModelForm):
2✔
109
    def __init__(self, *args, **kwargs):
2✔
110
        super().__init__(*args, **kwargs)
×
111
        self.helper = FormHelper()
×
112
        
113
        # Determine header class and active state based on whether form has data
114
        header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue'
×
115
        is_active = bool(self.instance and self.instance.pk)
×
116
        
117
        self.helper.layout = Layout(
×
118
            Field('name'),
119
            Accordion(
120
                AccordionGroup(
121
                    'POW Details',
122
                    Field('nearest_city'),
123
                    Field('notes'),
124
                    Field('wartime_country'),
125
                    Field('latitude'),
126
                    Field('longitude'),
127
                    active=is_active,
128
                    button_class=header_class
129
                ),
130
                css_id="powcamp-details-accordion"
131
            )
132
        )
133

134
    name = forms.CharField(
2✔
135
        widget=forms.TextInput(attrs={
136
            'class': 'wide-input'
137
        })
138
    )
139
    nearest_city = forms.CharField(
2✔
140
        widget=forms.TextInput(attrs={
141
            'class': 'wide-input'
142
        }),
143
        required=False
144
    )
145
    notes = forms.CharField(
2✔
146
        widget=forms.Textarea(attrs={
147
            'class': 'wide-input'
148
        }),
149
        required=False
150
    )
151
    wartime_country = forms.CharField(
2✔
152
        widget=forms.TextInput(attrs={
153
            'class': 'wide-input'
154
        }),
155
        required=False
156
    )
157
    latitude = forms.CharField(
2✔
158
        widget=forms.TextInput(attrs={
159
            'class': 'wide-input'
160
        }),
161
        required=False
162
    )
163
    longitude = forms.CharField(
2✔
164
        widget=forms.TextInput(attrs={
165
            'class': 'wide-input'
166
        }),
167
        required=False
168
    )
169

170
    class Meta:
2✔
171
        model = PowCamp
2✔
172
        fields = '__all__'
2✔
173

174

175
class editCemeteryForm(forms.ModelForm):
2✔
176
    name = forms.CharField(
2✔
177
        widget=forms.TextInput(attrs={
178
            'class': 'wide-input',
179
            'style': 'width: 500px;'
180
        })
181
    )
182
    country = forms.ModelChoiceField(
2✔
183
        queryset=Country.objects.all().order_by('name'),
184
        empty_label="Select a country"
185
    )
186

187
    class Meta:
2✔
188
        model = Cemetery
2✔
189
        fields = ['name', 'country', 'latitude', 'longitude']
2✔
190

191

192
class editCountryForm(forms.ModelForm):
2✔
193
    def __init__(self, *args, **kwargs):
2✔
194
        super().__init__(*args, **kwargs)
×
195
        self.helper = FormHelper()
×
196
        self.helper.label_class = 'form-label'  
×
197
    class Meta:
2✔
198
        model = Country
2✔
199
        fields = "__all__"
2✔
200

201
class editAcknowledgementForm(forms.ModelForm):
2✔
202
    def __init__(self, *args, **kwargs):
2✔
203
        super().__init__(*args, **kwargs)
×
204
        self.helper = FormHelper()
×
205
        self.helper.label_class = 'form-label'  
×
206
    class Meta:
2✔
207
        model = Acknowledgement
2✔
208
        created_at = forms.DateTimeField(disabled=True, required=False)
2✔
209
        exclude = ['created_at']  # This will hide created_at from the form
2✔
210
        fields = '__all__'
2✔
211

212

213
class editCompanyForm(forms.ModelForm):
2✔
214
    def __init__(self, *args, **kwargs):
2✔
215
        super().__init__(*args, **kwargs)
×
216
        self.helper = FormHelper()
×
217
        self.helper.label_class = 'form-label'  
×
218
    class Meta:
2✔
219
        model = Company 
2✔
220
        fields = "__all__"
2✔
221

222
class editDecorationForm(forms.ModelForm):
2✔
223
    def __init__(self, *args, **kwargs):
2✔
224
        super().__init__(*args, **kwargs)
×
225
        self.helper = FormHelper()
×
226
        self.helper.label_class = 'form-label'  
×
227
    class Meta:
2✔
228
        model = Decoration
2✔
229
        fields = "__all__"
2✔
230

231

232
class editRankForm(forms.ModelForm):
2✔
233
    name = forms.CharField(
2✔
234
        widget=forms.TextInput(attrs={
235
            'class': 'wide-input',
236
        })
237
    )
238

239
    class Meta:
2✔
240
        model = Rank
2✔
241
        fields = '__all__'
2✔
242

243

244
class editSoldierDeathForm(forms.ModelForm):
2✔
245
    class Meta:
2✔
246
        model = SoldierDeath
2✔
247
        fields = ['date', 'company', 'cemetery', 'cwgc_id', 'image']
2✔
248
        widgets = {
2✔
249
            'date': forms.DateInput(
250
                attrs={
251
                    'type': 'date',
252
                    'class': 'form-control'
253
                }
254
            )
255
        }
256
        labels = {
2✔
257
            'image': 'Grave Photograph'  # Updated label
258
        }
259

260
    def __init__(self, *args, **kwargs):
2✔
261
        super().__init__(*args, **kwargs)
×
NEW
262
        self.helper = SoldierDeathFormHelper()
×
NEW
263
        self.helper.form = self
×
NEW
264
        self.helper.update_title()
×
265

266

267
class editSoldierForm(forms.ModelForm):
2✔
268
    def __init__(self, *args, **kwargs):
2✔
269
        super().__init__(*args, **kwargs)
×
270
        self.helper = FormHelper()
×
271
        self.helper.label_class = 'form-label'  
×
NEW
272
        self.fields['provost_officer'].disabled = True
×
273

274
        # Determine header class and active state based on whether form has data
275
        header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue'
×
276
        is_active = bool(self.instance and self.instance.pk)
×
277
        
278
        # Check if there are any imprisonment records
279
        has_imprisonment = False
×
280
        if self.instance and self.instance.pk:
×
281
            has_imprisonment = SoldierImprisonment.objects.filter(soldier=self.instance).exists()
×
282
        
283
        # Set title based on whether there's data
284
        title = 'Prisoner of War Details' if has_imprisonment else 'Prisoner of War Details (None Recorded)'
×
285
        
286
        self.helper.layout = Layout(
×
287
            Field('surname'),
288
            Field('initials'),
289
            Field('army_number'),
290
            Field('rank'),
291
            Field('provost_officer'),
292
            Field('notes'),
293
            Accordion(
294
                AccordionGroup(
295
                    title,
296
                    'imprisonment_formset',
297
                    active=has_imprisonment,
298
                    button_class=header_class
299
                ),
300
                css_id="imprisonment-details-accordion"
301
            )
302
        )
303
        # Initialize the formset
304
        self.imprisonment_formset = SoldierImprisonmentInlineFormSet(
×
305
            instance=self.instance,
306
            prefix='imprisonment'
307
        )
308

309
    class Meta:
2✔
310
        model = Soldier
2✔
311
        exclude = ['created_at']  # Exclude the created_at field
2✔
312

313

314
class ProvostOfficerForm(forms.ModelForm):
2✔
315
    def __init__(self, *args, **kwargs):
2✔
316
        super().__init__(*args, **kwargs)
×
317
        self.helper = FormHelper()
×
318
        self.helper.label_class = 'form-label'  
×
319
        super().__init__(*args, **kwargs)
×
320
        self.fields['rank'].queryset = Rank.objects.filter(rank_class="OF").order_by('name')
×
321
    provost_officer = forms.BooleanField(
2✔
322
        initial=True,
323
        disabled=True,
324
        required=True,
325
        help_text="All officers created through this form are automatically marked as Provost Officers"
326
    )
327
    class Meta:
2✔
328
        model = Soldier
2✔
329
        fields = ['surname', 'initials', 'army_number', 'rank', 'provost_officer', 'notes']
2✔
330
        widgets = {
2✔
331
            'notes': forms.Textarea(attrs={'rows': 3}),
332
        }
333
    def save(self, commit=True):
2✔
334
        soldier = super().save(commit=False)
×
335
        soldier.provost_officer = True  # Set provost_officer to True
×
336
        print(soldier)
×
337
        if commit:
×
338
            soldier.save()
×
339
        return soldier
×
340

341

342
class ProvostAppointmentForm(forms.ModelForm):
2✔
343
    def __init__(self, *args, **kwargs):
2✔
344
        super().__init__(*args, **kwargs)
×
345
        self.helper = FormHelper()
×
346
        self.helper.label_class = 'form-label'  
×
347
        
348
    class Meta:
2✔
349
        model = ProvostAppointment
2✔
350
        fields = ['rank', 'date', 'notes']
2✔
351
        widgets = {
2✔
352
            'notes': forms.Textarea(attrs={'rows': 3}),
353
        }
354

355
class AcknowledgementForm(forms.ModelForm):
2✔
356
    class Meta:
2✔
357
        model = Acknowledgement
2✔
358
        fields = ['surname', 'name', 'notes']
2✔
359

360
class SoldierForm(forms.ModelForm):
2✔
361
    def __init__(self, *args, **kwargs):
2✔
362
        super().__init__(*args, **kwargs)
×
363
        self.helper = FormHelper()
×
364

365
        
366
        # Determine header class and active state based on whether form has data
367
        header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue'
×
368
        is_active = bool(self.instance and self.instance.pk)
×
369
        
370
        self.helper.layout = Layout(
×
371
            Field('surname'),
372
            Field('initials'),
373
            Field('army_number'),
374
            Field('rank'),
375
            #Field('provost_officer'),
376
            Field('notes'),
377
            Accordion(
378
                AccordionGroup(
379
                    'Prisoner of War Details',
380
                    'imprisonment_formset',
381
                    active=is_active,
382
                    button_class=header_class
383
                ),
384
                css_id="imprisonment-details-accordion"
385
            )
386
        )
387
        # Initialize the formset
388
        self.imprisonment_formset = SoldierImprisonmentInlineFormSet(
×
389
            instance=self.instance,
390
            prefix='imprisonment'
391
        )
392

393
    class Meta:
2✔
394
        model = Soldier
2✔
395
        fields = ['surname', 'initials', 'army_number', 'rank', 'provost_officer', 'notes']
2✔
396

397

398
class SoldierDecorationForm(forms.ModelForm):
2✔
399
    class Meta:
2✔
400
        model = SoldierDecoration
2✔
401
        fields = ['decoration', 'gazette_issue', 'gazette_page', 'gazette_date', 'theatre', 'country', 'citation', 'notes']
2✔
402
        widgets = {
2✔
403
            'gazette_date': forms.DateInput(
404
                attrs={
405
                    'type': 'date',
406
                    'class': 'form-control'
407
                }
408
            )
409
        }
410

411
class SoldierDecorationFormSetHelper(FormHelper):
2✔
412
    def __init__(self, *args, **kwargs):
2✔
UNCOV
413
        super().__init__(*args, **kwargs)
×
UNCOV
414
        self.form_tag = False
×
415
        
416
        # Default to collapsed
UNCOV
417
        has_data = False
×
NEW
418
        title = 'Decoration Details (None Recorded)'
×
419
        
UNCOV
420
        self.layout = Layout(
×
421
            Accordion(
422
                AccordionGroup(
423
                    title,
424
                    'decoration',
425
                    'gazette_issue',
426
                    'gazette_page',
427
                    'gazette_date',
428
                    'theatre',
429
                    'country',
430
                    'citation',
431
                    'notes',
432
                    active=has_data,
433
                    css_class='bg-info bg-opacity-25 border rounded p-3'
434
                ),
435
                css_id="decoration-details-accordion"
436
            )
437
        )
438

439
    def update_title(self):
2✔
NEW
440
        if hasattr(self, 'formset') and self.formset.initial_forms:
×
NEW
441
            has_data = any(form.initial for form in self.formset.initial_forms)
×
NEW
442
            title = 'Decoration Details' if has_data else 'Decoration Details (None Recorded)'
×
NEW
443
            self.layout[0][0].name = title
×
NEW
444
            self.layout[0][0].active = has_data
×
445

446
# Create the formset
447
SoldierDecorationInlineFormSet = inlineformset_factory(
2✔
448
    Soldier,
449
    SoldierDecoration,
450
    form=SoldierDecorationForm,
451
    extra=1,
452
    can_delete=True
453
)
454

455

456
class SoldierDeathFormHelper(FormHelper):
2✔
457
    def __init__(self, *args, **kwargs):
2✔
NEW
458
        super().__init__(*args, **kwargs)
×
NEW
459
        self.form_tag = False
×
460
        
461
        # Default to collapsed
NEW
462
        has_data = False
×
NEW
463
        title = 'Death Details (None Recorded)'
×
464
        
NEW
465
        self.layout = Layout(
×
466
            Accordion(
467
                AccordionGroup(
468
                    title,
469
                    'date',
470
                    'company',
471
                    'cemetery',
472
                    'cwgc_id',
473
                    'image',
474
                    active=has_data,  # Collapsed by default
475
                    css_class='bg-info bg-opacity-25 border rounded p-3'
476
                ),
477
                css_id="death-details-accordion"
478
            )
479
        )
480

481
    def update_title(self):
2✔
482
        """Update the title based on form data"""
NEW
483
        if hasattr(self, 'form') and self.form.initial:
×
NEW
484
            has_data = any(self.form.initial.values())
×
NEW
485
            title = 'Death Details' if has_data else 'Death Details (None Recorded)'
×
NEW
486
            self.layout[0][0].name = title
×
NEW
487
            self.layout[0][0].active = has_data
×
488

489

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc