Allow customising ticketing fee calculation

Existing ticketing fees can be preserved at database migration time
This commit is contained in:
Yingtong Li 2023-04-30 23:12:18 +10:00
parent faa81ca803
commit 0622ac2a89
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
6 changed files with 26 additions and 7 deletions

View File

@ -1,5 +1,6 @@
# Society Self-Service # Society Self-Service
# Copyright © 2018-2019 Yingtong Li (RunasSudo) # Copyright © 2018-2023 Yingtong Li (RunasSudo)
# Copyright © 2023 MUMUS Inc.
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published by
@ -32,6 +33,9 @@ PROMO_LOGO_URL = 'https://placehold.it/2000x500'
PROMO_LOGO_LINK = 'https://example.com' PROMO_LOGO_LINK = 'https://example.com'
PROMO_GROUPS_MANDATORY = ['All Years'] PROMO_GROUPS_MANDATORY = ['All Years']
TICKETING_FEE_PROPORTION = 0.0175 # Previous default was (1-1/1.01884)
TICKETING_FEE_FIXED = 0.30 # Previous default was 0.8133/1.01884
ABA_USER_NAME = 'Society Name' ABA_USER_NAME = 'Society Name'
ABA_BANK_NAME = 'CBA' ABA_BANK_NAME = 'CBA'
ABA_BANK_CODE = 0 ABA_BANK_CODE = 0

View File

@ -225,9 +225,12 @@
} }
}); });
const ticketingFeeProportion = {{ settings.TICKETING_FEE_PROPORTION }};
const ticketingFeeFixed = {{ settings.TICKETING_FEE_FIXED }};
const editing = true;
var revenue_data = JSON.parse({{ import('json').dumps(import('json').dumps(revision.revenue))|safe }}); var revenue_data = JSON.parse({{ import('json').dumps(import('json').dumps(revision.revenue))|safe }});
var expense_data = JSON.parse({{ import('json').dumps(import('json').dumps(revision.expense))|safe }}); var expense_data = JSON.parse({{ import('json').dumps(import('json').dumps(revision.expense))|safe }});
var editing = true;
makeGrid(); makeGrid();
dragula([document.querySelector('#revenue_grid tbody')], { dragula([document.querySelector('#revenue_grid tbody')], {

View File

@ -385,9 +385,13 @@
<script src="{{ static('sstreasury/budget.js') }}"></script> <script src="{{ static('sstreasury/budget.js') }}"></script>
<script> <script>
const ticketingFeeProportion = {{ revision.ticketing_fee_proportion }};
const ticketingFeeFixed = {{ revision.ticketing_fee_fixed }};
const editing = false;
var revenue_data = JSON.parse({{ import('json').dumps(import('json').dumps(revision.revenue))|safe }}); var revenue_data = JSON.parse({{ import('json').dumps(import('json').dumps(revision.revenue))|safe }});
var expense_data = JSON.parse({{ import('json').dumps(import('json').dumps(revision.expense))|safe }}); var expense_data = JSON.parse({{ import('json').dumps(import('json').dumps(revision.expense))|safe }});
var editing = false;
makeGrid(); makeGrid();
makeCharts(); makeCharts();
</script> </script>

View File

@ -1,5 +1,6 @@
# Society Self-Service # Society Self-Service
# Copyright © 2018–2022 Yingtong Li (RunasSudo) # Copyright © 2018–2023 Yingtong Li (RunasSudo)
# Copyright © 2023 MUMUS Inc.
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published by
@ -78,6 +79,9 @@ class BudgetRevision(models.Model):
expense_no_emergency_fund = models.BooleanField() expense_no_emergency_fund = models.BooleanField()
expense_comments = models.TextField() expense_comments = models.TextField()
ticketing_fee_proportion = models.FloatField()
ticketing_fee_fixed = models.FloatField()
action = models.IntegerField(choices=[(v.value, v.description) for v in BudgetAction]) action = models.IntegerField(choices=[(v.value, v.description) for v in BudgetAction])
class Meta: class Meta:
@ -103,7 +107,7 @@ class BudgetRevision(models.Model):
try: try:
total += Decimal(item['Unit price']) * Decimal(item['Units']) total += Decimal(item['Unit price']) * Decimal(item['Units'])
if item['IWT'] and item['Unit price'] > 0: if item['IWT'] and item['Unit price'] > 0:
total -= (Decimal(item['Unit price']) - (Decimal(item['Unit price']) - Decimal('0.8133')) / Decimal('1.01884')) * item['Units'] total -= (Decimal(item['Unit price']) * Decimal(self.ticketing_fee_proportion) + Decimal(self.ticketing_fee_fixed)) * item['Units']
except TypeError: except TypeError:
# Invalid unit price, etc. # Invalid unit price, etc.
pass pass

View File

@ -30,7 +30,7 @@ function recalcRevTotal(args) {
for (var row of args.grid.data) { for (var row of args.grid.data) {
revTotal += row['Unit price'] * row['Units']; revTotal += row['Unit price'] * row['Units'];
if (row['Unit price'] > 0 && row['IWT']) { if (row['Unit price'] > 0 && row['IWT']) {
revTotalIWT += (row['Unit price'] - (row['Unit price'] - 0.8133) / 1.01884) * row['Units']; revTotalIWT += (row['Unit price'] * ticketingFeeProportion + ticketingFeeFixed) * row['Units'];
} }
} }
@ -38,7 +38,7 @@ function recalcRevTotal(args) {
if (revTotalIWT > 0) { if (revTotalIWT > 0) {
var totalrow = $('<tr class="jsgrid-row totalrow" style="font-style: italic;"></tr>'); var totalrow = $('<tr class="jsgrid-row totalrow" style="font-style: italic;"></tr>');
totalrow.append($('<td class="jsgrid-cell">Less IWT fees:</td>').prop('colspan', args.grid.fields.length - (editing ? 2 : 1))); totalrow.append($('<td class="jsgrid-cell">Less ticketing fees:</td>').prop('colspan', args.grid.fields.length - (editing ? 2 : 1)));
totalrow.append($('<td class="jsgrid-cell jsgrid-align-right"></td>').text('($' + revTotalIWT.toFixed(2) + ')')); totalrow.append($('<td class="jsgrid-cell jsgrid-align-right"></td>').text('($' + revTotalIWT.toFixed(2) + ')'));
if (editing) { if (editing) {
totalrow.append($('<td class="jsgrid-cell"></td>')); totalrow.append($('<td class="jsgrid-cell"></td>'));

View File

@ -296,6 +296,8 @@ def budget_new(request):
revision = models.BudgetRevision() revision = models.BudgetRevision()
revision.author = request.user revision.author = request.user
revision.time = timezone.now() revision.time = timezone.now()
revision.ticketing_fee_proportion = settings.TICKETING_FEE_PROPORTION
revision.ticketing_fee_fixed = settings.TICKETING_FEE_FIXED
revision.action = models.BudgetAction.CREATE.value revision.action = models.BudgetAction.CREATE.value
revision.state = models.BudgetState.DRAFT.value revision.state = models.BudgetState.DRAFT.value
revision = revision_from_form(budget, revision, request.POST) revision = revision_from_form(budget, revision, request.POST)
@ -335,6 +337,8 @@ def budget_edit(request, budget, revision):
new_revision = models.BudgetRevision() new_revision = models.BudgetRevision()
new_revision.author = request.user new_revision.author = request.user
new_revision.time = timezone.now() new_revision.time = timezone.now()
new_revision.ticketing_fee_proportion = settings.TICKETING_FEE_PROPORTION
new_revision.ticketing_fee_fixed = settings.TICKETING_FEE_FIXED
new_revision.action = models.BudgetAction.EDIT.value new_revision.action = models.BudgetAction.EDIT.value
new_revision.state = revision.state new_revision.state = revision.state
new_revision = revision_from_form(budget, new_revision, request.POST) new_revision = revision_from_form(budget, new_revision, request.POST)