Skip to content

Commit

Permalink
Merge f687d78 into 9ab09ce
Browse files Browse the repository at this point in the history
  • Loading branch information
kendallcorner committed May 10, 2018
2 parents 9ab09ce + f687d78 commit a52a3a8
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 81 deletions.
4 changes: 3 additions & 1 deletion payments/management/commands/calculate.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pprint
from decimal import Decimal

from django.core.management.base import BaseCommand

Expand All @@ -10,9 +11,10 @@
class Command(BaseCommand):

def add_arguments(self, parser):
parser.add_argument('amount', nargs='+', type=int)
parser.add_argument('amount', nargs='+', type=float)

def handle(self, *args, **options):
amount = options['amount'][0]
amount = Decimal (amount)
details = utils.transaction_amounts(amount)
pp.pprint(details)
Empty file added payments/test.txt
Empty file.
93 changes: 72 additions & 21 deletions payments/tests/util_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,97 @@

from .. import utils

#import csv

class PaymentAmountTest(TestCase):

def test_calculate_amounts(self):
amounts = range(1, 1000)
#with open('new_tests.csv', 'wb') as csvfile:
#fieldnames = 'amount', 'charge_amount', 'payout_amount', 'codesy_fee', 'total_stripe_fee', 'offer_stripe_fee' , 'payout_stripe_fee', 'offer_fee', 'payout_fee', 'application_fee', 'gross_transfer_fee', 'actual_transfer_fee', 'charge_stripe_fee','payout_alt_calc', 'payout_overage', 'miscalculation_of_total_stripe_fee', 'iterations'
#test_writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
#test_writer.writeheader()
nonconvergances=0
nonconvergance_rate=0
amount_count=0

for amount in amounts:
print "---"
offer_values = utils.transaction_amounts(amount)
#test_writer.writerow(offer_values)

for comp in offer_values:
print u'%s : %s' % (comp, offer_values[comp])

offer_components = (
amount
+ offer_values['codesy_fee']
+ offer_values['offer_stripe_fee']
#Application fee is made up of 2 codesyfees, the fee from stripe for
#the credit card charnge, and the fee from stripe for the transfer
application_fee_components = (
2*offer_values['codesy_fee'] +
offer_values['charge_stripe_fee'] +
offer_values['actual_transfer_fee']
)

self.assertEqual(
application_fee_components,
offer_values['application_fee']
)

#Application fee is also made up of the total fees the offer is
#covering and the total fees the payout is covering.
application_fee_components = (
offer_values['offer_fee'] +
offer_values['payout_fee']
)

self.assertEqual(
offer_components,
application_fee_components,
offer_values['application_fee']
)

#The amount and offer fees always add up to the charge amount
self.assertEqual(
amount + offer_values['offer_fee'],
offer_values['charge_amount']
)

payout_components = (
amount
- offer_values['codesy_fee']
- offer_values['payout_stripe_fee']
#The payout amount and fees add up to the amount, unless the
#application fee has an odd penny.
payout_test = abs(offer_values['payout_amount'] + offer_values['payout_fee'] - amount) <= 0.01

self.assertEqual(
True,
payout_test
)

#The payout amount and application fee should add up to the charge amount
#unless the solution does not coverge.
application_fee_test = abs(offer_values['payout_amount'] + offer_values['application_fee'] - offer_values['charge_amount']) <= 0.01

self.assertEqual(
payout_components,
offer_values['payout_amount']
True,
application_fee_test
)

#The non-covergance rate should be low
amount_count += 1.0

payout_test = (offer_values['payout_amount'] + offer_values['payout_fee'] == amount)

application_fee_test = (offer_values['payout_amount'] + offer_values['application_fee'] == offer_values['charge_amount'])

if not(payout_test and application_fee_test):
nonconvergances += 1.0

nonconvergance_rate = float(nonconvergances/amount_count)
print u'n nonconvergances = %s, amount_count = %s, nonconvergance_rate = %s' % (nonconvergances, amount_count, nonconvergance_rate)

self.assertEqual(
offer_values['payout_amount'],
(offer_values['charge_amount']
- offer_values['application_fee']
)
True,
nonconvergance_rate < (2.0/500)
)



def test_fixed_amounts(self):
values = utils.transaction_amounts(10)
self.assertEqual(values['total_stripe_fee'], Decimal('0.66'))
Expand All @@ -56,11 +107,11 @@ def test_fixed_amounts(self):
self.assertEqual(values['actual_transfer_fee'], Decimal('0.05'))

values = utils.transaction_amounts(50)
self.assertEqual(values['total_stripe_fee'], Decimal('2.08'))
self.assertEqual(values['application_fee'], Decimal('4.58'))
self.assertEqual(values['total_stripe_fee'], Decimal('2.06'))
self.assertEqual(values['application_fee'], Decimal('4.56'))
self.assertEqual(values['codesy_fee'], Decimal('1.25'))
self.assertEqual(values['charge_amount'], Decimal('52.29'))
self.assertEqual(values['offer_stripe_fee'], Decimal('1.04'))
self.assertEqual(values['payout_amount'], Decimal('47.71'))
self.assertEqual(values['payout_stripe_fee'], Decimal('1.04'))
self.assertEqual(values['charge_amount'], Decimal('52.28'))
self.assertEqual(values['offer_stripe_fee'], Decimal('1.03'))
self.assertEqual(values['payout_amount'], Decimal('47.72'))
self.assertEqual(values['payout_stripe_fee'], Decimal('1.03'))
self.assertEqual(values['actual_transfer_fee'], Decimal('0.24'))
148 changes: 89 additions & 59 deletions payments/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
from django.conf import settings

import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
#stripe.api_key = settings.STRIPE_SECRET_KEY

# codesy fee of 2.5% charged to offer and payout
codesy_pct = Decimal('0.025')
#codesy_pct = Decimal('0.05')

# stripe charge of 2.9% for credit card payments
stripe_pct = Decimal('0.029')
Expand All @@ -21,86 +22,115 @@ def round_penny(amount):
return amount.quantize(Decimal('.01'), rounding=ROUND_HALF_UP)


def calculate_codesy_fee(amount):
def calculate_half_codesy_fee(amount):
return round_penny(amount * codesy_pct)


def calculate_stripe_fee(amount):
def calculate_charge_stripe_fee(offer_charge):
return round_penny(
(amount * (stripe_pct + stripe_transfer_pct)) + stripe_transaction
offer_charge * stripe_pct + stripe_transaction
)


def calculate_stripe_transfer(amount):
return round_penny(amount * stripe_transfer_pct)


def calculate_charge_amount(goal):
def calculate_transfer_stripe_fee(payout_amount):
return round_penny(
(goal + stripe_transaction) / (1 - stripe_pct)
)


def calculate_offer_charge(goal):
return round_penny(
(goal + (stripe_transaction / 2))
/ (1 - ((stripe_pct + stripe_transfer_pct) / 2))
payout_amount * stripe_transfer_pct
)


def transaction_amounts(amount):
codesy_fee_amount = calculate_codesy_fee(amount)

charge_amount = calculate_offer_charge(
amount
+ codesy_fee_amount
#if amount <= 0:
# raise ValueError('Zeros and negatives are not allowed')
charge_guess = 0
payout_guess = 0
half_codesy_fee_amount = calculate_half_codesy_fee(amount)
#Codesy's total 5% fee.
charge_stripe_fee = 0
#Stripe's actual fee on the charged amount--should equal Stripe's info.
transfer_stripe_fee = 0
#Stripe's actual fee on the payout amount--should equal Stripe's info.
application_fee = 0
#total fees taken out
#Information given to Stripe
iteration = 0
calc_charge = 0
calc_payout = 0

# |--F--|
# -+------------+--+--+----
# 0 T A C
#
# A = agreed amount
# C = charge = A + 1/2*F
# T = payout transfer = A - 1/2*F
# F = Fees = rp(C*r_sc + f_sc) + rp(A*r_c) + rp(T*r_st)
# r_sc = stripe rate for charges
# f_sc = stripe flat fee for charges
# r_st = stripe rate for payout transfers
# r_c = codesy rate
# rp = round_penny function rounds to the nearest penney

for iteration in range(0,11):
#used a while originally, but sometimes the while gets stuck
charge_guess = calc_charge
payout_guess = calc_payout
charge_stripe_fee = calculate_charge_stripe_fee(charge_guess)
transfer_stripe_fee = calculate_transfer_stripe_fee(payout_guess)
application_fee = 2*half_codesy_fee_amount + charge_stripe_fee + transfer_stripe_fee
calc_charge = round_penny(amount + application_fee / 2)
calc_payout = round_penny(calc_charge - application_fee)
#Note: when total fees are uneven, charge gets the extra penny
if (charge_guess == calc_charge) and (payout_guess == calc_payout):
#breaks out when guess and calc are equal
break

charge_amount = charge_guess
#Amount charged to the bidder/offerer's card or account
#information given to Stripe

payout_amount = payout_guess
#Amount that ends up in the asker/fixer's bank account

offer_fee = round_penny(application_fee/2)
# Part of the fee-split added on to offer. Calculated for testing purposes. Note: when total fees are uneven, offer gets the extra penny

offer_stripe_fee = offer_fee - half_codesy_fee_amount

payout_fee = application_fee - offer_fee
#part of the fee-split taken out of payout. Calculated for testing purposes. Note: when total fees are uneven, offer gets the extra penny

payout_stripe_fee = payout_fee - half_codesy_fee_amount

payout_alt_calc = (
charge_amount - application_fee
)
#back calculating payout for testing

offer_stripe_fee = (
charge_amount
- amount
- codesy_fee_amount
payout_overage = (
payout_alt_calc
- payout_amount
)

total_stripe_fee = calculate_stripe_fee(charge_amount)

payout_stripe_fee = total_stripe_fee - offer_stripe_fee

payout_amount = (
amount
- codesy_fee_amount
- payout_stripe_fee
)

application_fee = (
offer_stripe_fee
+ payout_stripe_fee
+ (codesy_fee_amount * 2)
)

gross_transfer_fee = calculate_stripe_transfer(amount)

actual_transfer_fee = (
calculate_stripe_transfer(payout_amount)
)

transfer_overage = (
gross_transfer_fee
- actual_transfer_fee
)
total_stripe_fee = charge_stripe_fee + transfer_stripe_fee

return {
'amount': amount,
'charge_amount': round_penny(charge_amount),
'charge_amount': charge_amount,
'payout_amount': payout_amount,
'codesy_fee': codesy_fee_amount,
'codesy_fee': half_codesy_fee_amount,
'total_stripe_fee': total_stripe_fee,
'offer_stripe_fee': offer_stripe_fee,
'payout_stripe_fee': payout_stripe_fee,
'offer_stripe_fee': offer_stripe_fee, # offer's half of total stripe fees
'payout_stripe_fee': payout_stripe_fee, # payout's half of total stripe fees
'charge_stripe_fee': charge_stripe_fee, # Stripe's fee on the credit card charge
'gross_transfer_fee': calculate_transfer_stripe_fee(payout_alt_calc),
'actual_transfer_fee': transfer_stripe_fee, # Stripe's fee on the payout transfer
'offer_fee': offer_fee, # total fees given to offer
'payout_fee': payout_fee, # total fees given to payout
'application_fee': application_fee,
'gross_transfer_fee': gross_transfer_fee,
'actual_transfer_fee': actual_transfer_fee,
'transfer_overage': transfer_overage
'payout_alt_calc': payout_alt_calc,
'payout_overage': payout_overage,
'miscalculation_of_total_stripe_fee': total_stripe_fee - charge_stripe_fee - transfer_stripe_fee,
'iterations': iteration
}


Expand Down

0 comments on commit a52a3a8

Please sign in to comment.