From ca3d7b0d9ca0befa42f4897fbb64e3fabd04f62f Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Sat, 16 Apr 2016 21:30:56 -0400 Subject: [PATCH] up wall of shame fee to 5% + 5% also charge on slipping past $-5 --- chezbetty/datalayer.py | 56 +++++++++++++++++++++-- chezbetty/models/model.py | 1 + chezbetty/static/js/chezbetty-terminal.js | 49 ++++++++++++++++---- chezbetty/templates/public/about.jinja2 | 2 +- chezbetty/views_terminal.py | 2 +- 5 files changed, 95 insertions(+), 15 deletions(-) diff --git a/chezbetty/datalayer.py b/chezbetty/datalayer.py index 67f4c1a..c87fafd 100644 --- a/chezbetty/datalayer.py +++ b/chezbetty/datalayer.py @@ -168,11 +168,61 @@ def purchase(user, account, items): assert(len(items) > 0) # TODO: Parameterize - discount = None + discount = Decimal(0) if user.balance > 20.0: discount = Decimal('0.05') - elif user.balance <= -5.0: - discount = round(Decimal('-0.01')*(5 + math.floor((user.balance+5) / -5)), 2) + + # Need to calculate a total + amount = Decimal(0) + for item, quantity in items.items(): + amount += Decimal(item.price * quantity) + + intermediate = amount - (amount * discount).quantize(Decimal('.01'), rounding=ROUND_HALF_UP) + + # Calculate a potential wall of shame fee + fee = None + fee_amount = Decimal(0) + result = user.balance - intermediate + fee_percent = Decimal(0) + if result <= Decimal('-5'): + remainder = (user.balance - intermediate) * Decimal('-1') + offset = user.balance * Decimal('-1') + if user.balance > Decimal('-5'): + offset = Decimal('5') + fee_percent = math.floor(offset / Decimal('5')) * Decimal('5') + + while True: + extra = remainder - offset + + if remainder < fee_percent + Decimal('5'): + fee_amount += ((fee_percent * Decimal('0.01')) * extra) + break + + else: + fee_amount += ((fee_percent * Decimal('0.01')) * (fee_percent + Decimal('5') - offset)) + fee_percent += Decimal('5') + offset = fee_percent + + fee_percent = (fee_amount / intermediate) * Decimal('100') + if fee_percent < Decimal('0.1'): + fee_percent = Decimal('0.1') + + fee_amount = (intermediate * (fee_percent * Decimal('0.01'))).quantize(Decimal('.01'), rounding=ROUND_HALF_UP) + + + if fee_amount != 0: + if discount != 0: + # Only do this complicated math if we have to merge a good + # standing discount with a wall of shame fee + final = intermediate + fee_amount + discount = (-1 * ((final / amount) - Decimal('1'))) + else: + # Just use wall of shame fee + discount = fee_percent * Decimal('0.01') + + if discount == 0: + # Make sure we handle the no discount normal case correctly + discount = None e = event.Purchase(user) DBSession.add(e) diff --git a/chezbetty/models/model.py b/chezbetty/models/model.py index 8837af8..d75cc64 100644 --- a/chezbetty/models/model.py +++ b/chezbetty/models/model.py @@ -1,6 +1,7 @@ import datetime import functools from decimal import Decimal +from decimal import ROUND_HALF_UP import decimal from sqlalchemy import ( LargeBinary, diff --git a/chezbetty/static/js/chezbetty-terminal.js b/chezbetty/static/js/chezbetty-terminal.js index 1a1a1c9..a6afc1e 100644 --- a/chezbetty/static/js/chezbetty-terminal.js +++ b/chezbetty/static/js/chezbetty-terminal.js @@ -105,7 +105,7 @@ function calculate_total () { var discount_percent_td = $("#purchase-discount-percent"); var discount_percent_str = discount_percent_td.text().slice(1,-2); var discount_percent = parseFloat(discount_percent_str) * 0.01; - var discount = total * discount_percent; + var discount = Math.round((total * discount_percent) * 100) / 100; // Make sure nothing looks strange if (discount > total) discount = 0.0; @@ -118,10 +118,10 @@ function calculate_total () { $("#purchase-row-goodstanding").hide(); } - if (balance <= -5.0) { + if ((balance - total - discount) <= -5.0) { // Wall of shame fee! - var fee_percent = calculate_wallofshame_fee_percent(); - var fee = total * (fee_percent * 0.01); + var fee_percent = calculate_wallofshame_fee_percent(balance, total-discount); + var fee = Math.round(((total-discount) * (fee_percent * 0.01)) * 100) / 100; // Setup fee row $("#purchase-fee-percent-amount").html(fee_percent.toFixed(1)); @@ -267,14 +267,43 @@ function show_correct_purchase_button () { } } -function calculate_wallofshame_fee_percent () { - var balance = get_user_balance(); +function calculate_wallofshame_fee_percent (balance, total) { + // If not on wall of shame, nor going to be, no fee + if (balance - total > -5.0) return 0.0; + + // Calculate the correct fee. + // Need to get the amount we will charge the fee on + var remainder = (balance - total) * -1; + var offset = balance * -1; + if (balance > -5) { + offset = 5; + } + var fee_percent = Math.floor(offset / 5.0) * 5; + var fee = 0; - // If not on wall of shame, no fee - if (balance > -5.0) return 0.0; + // This works only because we increase the fee every $5 dollars + // and we increase the fee in 5% increments. + while (true) { + var extra = remainder - offset; + + if (remainder < fee_percent + 5) { + fee += ((fee_percent * 0.01) * extra); + break; + + } else { + fee += ((fee_percent * 0.01) * (fee_percent + 5 - offset)); + fee_percent += 5; + offset = fee_percent; + } + } + + fee_percent = (fee / total) * 100; + + if (fee_percent < 0.1) { + fee_percent = 0.1; + } - // Else, one percent for every $5 in debt after $-5, 5.0% to start - return 5.0 + Math.floor((balance+5.0) / -5.0); + return fee_percent; } /******************************************************************************* diff --git a/chezbetty/templates/public/about.jinja2 b/chezbetty/templates/public/about.jinja2 index 1d262de..cebafe3 100644 --- a/chezbetty/templates/public/about.jinja2 +++ b/chezbetty/templates/public/about.jinja2 @@ -97,7 +97,7 @@ {{ _("For people on the Wall of Shame (anyone with less than $5 in their account), Betty charges a progressive tax on all purchases.") + ' ' + - _("The tax begins at 5% and increases an additional 1% for every additional $5 you are in debt ($10-15 debt is 6%, $15-20 is 7%, and so on).") + _("The tax begins at 5% and increases an additional 5% for every additional $5 you are in debt ($10-15 debt is 10%, $15-20 is 15%, and so on).") + ' ' + _("If you are on the Wall of Shame, the Betty terminal will very clearly show the tax being applied as you check out.") }} diff --git a/chezbetty/views_terminal.py b/chezbetty/views_terminal.py index 34ed4af..5dceef3 100644 --- a/chezbetty/views_terminal.py +++ b/chezbetty/views_terminal.py @@ -100,7 +100,7 @@ def terminal(request): # Determine initial wall-of-shame fee (if applicable) purchase_fee_percent = Decimal(0) if user.balance <= Decimal('-5.0'): - purchase_fee_percent = 5 + math.floor((user.balance+5) / -5) + purchase_fee_percent = 5 + (math.floor((user.balance+5) / -5) * 5) # Figure out if any pools can be used to pay for this purchase purchase_pools = []