adapt and fix

testing
Christian Merten 2 months ago
parent ad33d5db17
commit 5edb897bc2
Signed by: christian.merten
GPG Key ID: D953D69721B948B3

@ -64,7 +64,7 @@ def decorate_statement_view(model, perm=None):
@admin.register(StatementUnSubmitted) @admin.register(StatementUnSubmitted)
class StatementUnSubmittedAdmin(CommonAdminMixin, admin.ModelAdmin): class StatementUnSubmittedAdmin(CommonAdminMixin, admin.ModelAdmin):
fields = ['short_description', 'explanation', 'excursion', 'submitted'] fields = ['short_description', 'explanation', 'excursion', 'status']
list_display = ['__str__', 'excursion', 'created_by'] list_display = ['__str__', 'excursion', 'created_by']
inlines = [BillOnStatementInline] inlines = [BillOnStatementInline]
@ -74,7 +74,7 @@ class StatementUnSubmittedAdmin(CommonAdminMixin, admin.ModelAdmin):
super().save_model(request, obj, form, change) super().save_model(request, obj, form, change)
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
readonly_fields = ['submitted', 'excursion'] readonly_fields = ['status', 'excursion']
if obj is not None and obj.submitted: if obj is not None and obj.submitted:
return readonly_fields + self.fields return readonly_fields + self.fields
else: else:
@ -167,7 +167,7 @@ class BillOnSubmittedStatementInline(BillOnStatementInline):
@admin.register(StatementSubmitted) @admin.register(StatementSubmitted)
class StatementSubmittedAdmin(admin.ModelAdmin): class StatementSubmittedAdmin(admin.ModelAdmin):
fields = ['short_description', 'explanation', 'excursion', 'submitted'] fields = ['short_description', 'explanation', 'excursion', 'status']
list_display = ['__str__', 'is_valid', 'submitted_date', 'submitted_by'] list_display = ['__str__', 'is_valid', 'submitted_date', 'submitted_by']
ordering = ('-submitted_date',) ordering = ('-submitted_date',)
inlines = [BillOnSubmittedStatementInline, TransactionOnSubmittedStatementInline] inlines = [BillOnSubmittedStatementInline, TransactionOnSubmittedStatementInline]
@ -186,7 +186,7 @@ class StatementSubmittedAdmin(admin.ModelAdmin):
return False return False
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
readonly_fields = ['submitted'] readonly_fields = ['status']
if obj is not None and obj.submitted: if obj is not None and obj.submitted:
return readonly_fields + self.fields return readonly_fields + self.fields
else: else:
@ -274,7 +274,7 @@ class StatementSubmittedAdmin(admin.ModelAdmin):
return HttpResponseRedirect(reverse('admin:%s_%s_changelist' % (self.opts.app_label, self.opts.model_name))) return HttpResponseRedirect(reverse('admin:%s_%s_changelist' % (self.opts.app_label, self.opts.model_name)))
if "reject" in request.POST: if "reject" in request.POST:
statement.submitted = False statement.status = Statement.UNSUBMITTED
statement.save() statement.save()
messages.success(request, messages.success(request,
_("Successfully rejected %(name)s. The requestor can reapply, when needed.") _("Successfully rejected %(name)s. The requestor can reapply, when needed.")
@ -315,7 +315,7 @@ class StatementSubmittedAdmin(admin.ModelAdmin):
@admin.register(StatementConfirmed) @admin.register(StatementConfirmed)
class StatementConfirmedAdmin(admin.ModelAdmin): class StatementConfirmedAdmin(admin.ModelAdmin):
fields = ['short_description', 'explanation', 'excursion', 'confirmed'] fields = ['short_description', 'explanation', 'excursion', 'status']
#readonly_fields = fields #readonly_fields = fields
list_display = ['__str__', 'total_pretty', 'confirmed_date', 'confirmed_by'] list_display = ['__str__', 'total_pretty', 'confirmed_date', 'confirmed_by']
ordering = ('-confirmed_date',) ordering = ('-confirmed_date',)
@ -365,7 +365,7 @@ class StatementConfirmedAdmin(admin.ModelAdmin):
_("%(name)s is not yet confirmed.") % {'name': str(statement)}) _("%(name)s is not yet confirmed.") % {'name': str(statement)})
return HttpResponseRedirect(reverse('admin:%s_%s_change' % (self.opts.app_label, self.opts.model_name), args=(statement.pk,))) return HttpResponseRedirect(reverse('admin:%s_%s_change' % (self.opts.app_label, self.opts.model_name), args=(statement.pk,)))
if "unconfirm" in request.POST: if "unconfirm" in request.POST:
statement.confirmed = False statement.status = Statement.SUBMITTED
statement.confirmed_date = None statement.confirmed_date = None
statement.confired_by = None statement.confired_by = None
statement.save() statement.save()

@ -0,0 +1,39 @@
# Generated by Django 4.2.20 on 2025-10-11 15:43
from django.db import migrations, models
def set_status_from_old_fields(apps, schema_editor):
"""
Set the status field based on the existing submitted and confirmed fields.
- If confirmed is True, status = CONFIRMED (2)
- If submitted is True but confirmed is False, status = SUBMITTED (1)
- Otherwise, status = UNSUBMITTED (0)
"""
Statement = apps.get_model('finance', 'Statement')
UNSUBMITTED, SUBMITTED, CONFIRMED = 0, 1, 2
for statement in Statement.objects.all():
if statement.confirmed:
statement.status = CONFIRMED
elif statement.submitted:
statement.status = SUBMITTED
else:
statement.status = UNSUBMITTED
statement.save(update_fields=['status'])
class Migration(migrations.Migration):
dependencies = [
('finance', '0009_statement_ljp_to'),
]
operations = [
migrations.AddField(
model_name='statement',
name='status',
field=models.IntegerField(choices=[(0, 'In preparation'), (1, 'Submitted'), (2, 'Confirmed')], default=0, verbose_name='Status'),
),
migrations.RunPython(set_status_from_old_fields, reverse_code=migrations.RunPython.noop),
]

@ -0,0 +1,21 @@
# Generated by Django 4.2.20 on 2025-10-11 16:01
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('finance', '0010_statement_status'),
]
operations = [
migrations.RemoveField(
model_name='statement',
name='confirmed',
),
migrations.RemoveField(
model_name='statement',
name='submitted',
),
]

@ -46,11 +46,15 @@ class TransactionIssue:
class StatementManager(models.Manager): class StatementManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(submitted=False, confirmed=False) return super().get_queryset().filter(status=Statement.UNSUBMITTED)
class Statement(CommonModel): class Statement(CommonModel):
MISSING_LEDGER, NON_MATCHING_TRANSACTIONS, INVALID_ALLOWANCE_TO, INVALID_TOTAL, VALID = 0, 1, 2, 3, 4 MISSING_LEDGER, NON_MATCHING_TRANSACTIONS, INVALID_ALLOWANCE_TO, INVALID_TOTAL, VALID = 0, 1, 2, 3, 4
UNSUBMITTED, SUBMITTED, CONFIRMED = 0, 1, 2
STATUS_CHOICES = [(UNSUBMITTED, _('In preparation')),
(SUBMITTED, _('Submitted')),
(CONFIRMED, _('Confirmed'))]
short_description = models.CharField(verbose_name=_('Short description'), short_description = models.CharField(verbose_name=_('Short description'),
max_length=30, max_length=30,
@ -82,9 +86,10 @@ class Statement(CommonModel):
night_cost = models.DecimalField(verbose_name=_('Price per night'), default=0, decimal_places=2, max_digits=5) night_cost = models.DecimalField(verbose_name=_('Price per night'), default=0, decimal_places=2, max_digits=5)
submitted = models.BooleanField(verbose_name=_('Submitted'), default=False) status = models.IntegerField(verbose_name=_('Status'),
choices=STATUS_CHOICES,
default=UNSUBMITTED)
submitted_date = models.DateTimeField(verbose_name=_('Submitted on'), default=None, null=True) submitted_date = models.DateTimeField(verbose_name=_('Submitted on'), default=None, null=True)
confirmed = models.BooleanField(verbose_name=_('Confirmed'), default=False)
confirmed_date = models.DateTimeField(verbose_name=_('Paid on'), default=None, null=True) confirmed_date = models.DateTimeField(verbose_name=_('Paid on'), default=None, null=True)
created_by = models.ForeignKey(Member, verbose_name=_('Created by'), created_by = models.ForeignKey(Member, verbose_name=_('Created by'),
@ -131,8 +136,16 @@ class Statement(CommonModel):
else: else:
return self.short_description return self.short_description
@property
def submitted(self):
return self.status == Statement.SUBMITTED or self.status == Statement.CONFIRMED
@property
def confirmed(self):
return self.status == Statement.CONFIRMED
def submit(self, submitter=None): def submit(self, submitter=None):
self.submitted = True self.status = self.SUBMITTED
self.submitted_date = timezone.now() self.submitted_date = timezone.now()
self.submitted_by = submitter self.submitted_by = submitter
self.save() self.save()
@ -231,7 +244,7 @@ class Statement(CommonModel):
if not self.validity == Statement.VALID: if not self.validity == Statement.VALID:
return False return False
self.confirmed = True self.status = self.CONFIRMED
self.confirmed_date = timezone.now() self.confirmed_date = timezone.now()
self.confirmed_by = confirmer self.confirmed_by = confirmer
for trans in self.transaction_set.all(): for trans in self.transaction_set.all():
@ -569,7 +582,7 @@ class Statement(CommonModel):
class StatementUnSubmittedManager(models.Manager): class StatementUnSubmittedManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(submitted=False, confirmed=False) return super().get_queryset().filter(status=Statement.UNSUBMITTED)
class StatementUnSubmitted(Statement): class StatementUnSubmitted(Statement):
@ -589,7 +602,7 @@ class StatementUnSubmitted(Statement):
class StatementSubmittedManager(models.Manager): class StatementSubmittedManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(submitted=True, confirmed=False) return super().get_queryset().filter(status=Statement.SUBMITTED)
class StatementSubmitted(Statement): class StatementSubmitted(Statement):
@ -606,7 +619,7 @@ class StatementSubmitted(Statement):
class StatementConfirmedManager(models.Manager): class StatementConfirmedManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(confirmed=True) return super().get_queryset().filter(status=Statement.CONFIRMED)
class StatementConfirmed(Statement): class StatementConfirmed(Statement):

@ -99,16 +99,16 @@ class StatementUnSubmittedAdminTestCase(AdminTestCase):
def test_get_readonly_fields_submitted(self): def test_get_readonly_fields_submitted(self):
"""Test readonly fields when statement is submitted""" """Test readonly fields when statement is submitted"""
# Mark statement as submitted # Mark statement as submitted
self.statement.submitted = True self.statement.status = Statement.SUBMITTED
readonly_fields = self.admin.get_readonly_fields(None, self.statement) readonly_fields = self.admin.get_readonly_fields(None, self.statement)
self.assertIn('submitted', readonly_fields) self.assertIn('status', readonly_fields)
self.assertIn('excursion', readonly_fields) self.assertIn('excursion', readonly_fields)
self.assertIn('short_description', readonly_fields) self.assertIn('short_description', readonly_fields)
def test_get_readonly_fields_not_submitted(self): def test_get_readonly_fields_not_submitted(self):
"""Test readonly fields when statement is not submitted""" """Test readonly fields when statement is not submitted"""
readonly_fields = self.admin.get_readonly_fields(None, self.statement) readonly_fields = self.admin.get_readonly_fields(None, self.statement)
self.assertEqual(readonly_fields, ['submitted', 'excursion']) self.assertEqual(readonly_fields, ['status', 'excursion'])
def test_submit_view_insufficient_permission(self): def test_submit_view_insufficient_permission(self):
url = reverse('admin:finance_statementunsubmitted_submit', url = reverse('admin:finance_statementunsubmitted_submit',
@ -163,7 +163,7 @@ class StatementSubmittedAdminTestCase(AdminTestCase):
self.statement = Statement.objects.create( self.statement = Statement.objects.create(
short_description='Submitted Statement', short_description='Submitted Statement',
explanation='Test explanation', explanation='Test explanation',
submitted=True, status=Statement.SUBMITTED,
submitted_by=self.member, submitted_by=self.member,
submitted_date=timezone.now(), submitted_date=timezone.now(),
night_cost=25 night_cost=25
@ -198,7 +198,7 @@ class StatementSubmittedAdminTestCase(AdminTestCase):
self.statement_no_trans_success = Statement.objects.create( self.statement_no_trans_success = Statement.objects.create(
short_description='No Transactions Success', short_description='No Transactions Success',
explanation='Test explanation', explanation='Test explanation',
submitted=True, status=Statement.SUBMITTED,
submitted_by=self.member, submitted_by=self.member,
submitted_date=timezone.now(), submitted_date=timezone.now(),
night_cost=25 night_cost=25
@ -206,7 +206,7 @@ class StatementSubmittedAdminTestCase(AdminTestCase):
self.statement_no_trans_error = Statement.objects.create( self.statement_no_trans_error = Statement.objects.create(
short_description='No Transactions Error', short_description='No Transactions Error',
explanation='Test explanation', explanation='Test explanation',
submitted=True, status=Statement.SUBMITTED,
submitted_by=self.member, submitted_by=self.member,
submitted_date=timezone.now(), submitted_date=timezone.now(),
night_cost=25 night_cost=25
@ -294,7 +294,7 @@ class StatementSubmittedAdminTestCase(AdminTestCase):
"""Test overview_view with statement that can't be found in StatementSubmitted queryset""" """Test overview_view with statement that can't be found in StatementSubmitted queryset"""
# When trying to access an unsubmitted statement via StatementSubmitted admin, # When trying to access an unsubmitted statement via StatementSubmitted admin,
# the decorator will fail to find it and show "Statement not found" # the decorator will fail to find it and show "Statement not found"
self.statement.submitted = False self.statement.status = Statement.UNSUBMITTED
self.statement.save() self.statement.save()
url = reverse('admin:finance_statementsubmitted_overview', args=(self.statement.pk,)) url = reverse('admin:finance_statementsubmitted_overview', args=(self.statement.pk,))
@ -496,8 +496,7 @@ class StatementConfirmedAdminTestCase(AdminTestCase):
base_statement = Statement.objects.create( base_statement = Statement.objects.create(
short_description='Confirmed Statement', short_description='Confirmed Statement',
explanation='Test explanation', explanation='Test explanation',
submitted=True, status=Statement.CONFIRMED,
confirmed=True,
confirmed_by=self.member, confirmed_by=self.member,
confirmed_date=timezone.now(), confirmed_date=timezone.now(),
night_cost=25 night_cost=25
@ -510,8 +509,7 @@ class StatementConfirmedAdminTestCase(AdminTestCase):
self.unconfirmed_statement = Statement.objects.create( self.unconfirmed_statement = Statement.objects.create(
short_description='Unconfirmed Statement', short_description='Unconfirmed Statement',
explanation='Test explanation', explanation='Test explanation',
submitted=True, status=Statement.SUBMITTED,
confirmed=False,
night_cost=25 night_cost=25
) )
@ -528,8 +526,7 @@ class StatementConfirmedAdminTestCase(AdminTestCase):
confirmed_with_excursion_base = Statement.objects.create( confirmed_with_excursion_base = Statement.objects.create(
short_description='Confirmed with Excursion', short_description='Confirmed with Excursion',
explanation='Test explanation', explanation='Test explanation',
submitted=True, status=Statement.CONFIRMED,
confirmed=True,
confirmed_by=self.member, confirmed_by=self.member,
confirmed_date=timezone.now(), confirmed_date=timezone.now(),
excursion=self.excursion, excursion=self.excursion,

@ -505,11 +505,11 @@ class ManagerTestCase(TestCase):
self.st_submitted = Statement.objects.create(short_description='A statement', self.st_submitted = Statement.objects.create(short_description='A statement',
explanation='Important!', explanation='Important!',
night_cost=0, night_cost=0,
submitted=True) status=Statement.SUBMITTED)
self.st_confirmed = Statement.objects.create(short_description='A statement', self.st_confirmed = Statement.objects.create(short_description='A statement',
explanation='Important!', explanation='Important!',
night_cost=0, night_cost=0,
confirmed=True) status=Statement.CONFIRMED)
def test_get_queryset(self): def test_get_queryset(self):
# TODO: remove this manager, since it is not used # TODO: remove this manager, since it is not used

@ -52,15 +52,15 @@ class FinanceRulesTestCase(TestCase):
def test_not_submitted_statement(self): def test_not_submitted_statement(self):
"""Test not_submitted predicate returns True when statement is not submitted""" """Test not_submitted predicate returns True when statement is not submitted"""
self.statement.submitted = False self.statement.status = Statement.UNSUBMITTED
self.assertTrue(not_submitted(self.user1, self.statement)) self.assertTrue(not_submitted(self.user1, self.statement))
self.statement.submitted = True self.statement.status = Statement.SUBMITTED
self.assertFalse(not_submitted(self.user1, self.statement)) self.assertFalse(not_submitted(self.user1, self.statement))
def test_not_submitted_freizeit_with_statement(self): def test_not_submitted_freizeit_with_statement(self):
"""Test not_submitted predicate with Freizeit having unsubmitted statement""" """Test not_submitted predicate with Freizeit having unsubmitted statement"""
self.freizeit.statement = self.statement self.freizeit.statement = self.statement
self.statement.submitted = False self.statement.status = Statement.UNSUBMITTED
self.assertTrue(not_submitted(self.user1, self.freizeit)) self.assertTrue(not_submitted(self.user1, self.freizeit))
def test_not_submitted_freizeit_without_statement(self): def test_not_submitted_freizeit_without_statement(self):

@ -88,12 +88,12 @@ class RulesTestCase(TestCase):
self.statement_unsubmitted = Statement.objects.create( self.statement_unsubmitted = Statement.objects.create(
short_description='Unsubmitted Statement', short_description='Unsubmitted Statement',
excursion=self.excursion, excursion=self.excursion,
submitted=False status=Statement.UNSUBMITTED
) )
self.statement_submitted = Statement.objects.create( self.statement_submitted = Statement.objects.create(
short_description='Submitted Statement', short_description='Submitted Statement',
submitted=True status=Statement.SUBMITTED
) )
def test_is_oneself(self): def test_is_oneself(self):

Loading…
Cancel
Save