Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

calculate fee properly in MassPay script #1673

Closed
chadwhitacre opened this issue Nov 14, 2013 · 26 comments
Closed

calculate fee properly in MassPay script #1673

chadwhitacre opened this issue Nov 14, 2013 · 26 comments

Comments

@chadwhitacre
Copy link
Contributor

It's calculated as a percentage on the individual payments, not on the total.

Reticketed from #1671 (comment) :

MassPay is off by a penny. :-/

@chadwhitacre
Copy link
Contributor Author

I tried levying the fee on the individual payments and am not seeing that it worked. :-/

I'm going to try uploading 12 spreadsheets, one for each payment, to compare the fee for each so I can pinpoint the problem.

@chadwhitacre
Copy link
Contributor Author

Found it! One of the twelve is off by one.

@chadwhitacre
Copy link
Contributor Author

And only that one is off.

@chadwhitacre
Copy link
Contributor Author

The target amount is 15.55, and we're calculating a 0.30 fee, but PayPal calculates a 0.31 fee on 15.25.

@chadwhitacre
Copy link
Contributor Author

15.25 * 0.02 == .305

@chadwhitacre
Copy link
Contributor Author

15.25 * 1.02 == 15.555
15.24 * 1.02 == 15.5448

@chadwhitacre
Copy link
Contributor Author

Sure feels like there's some math going on here ...

@chadwhitacre
Copy link
Contributor Author

So if we drop back to 15.24 we come out a penny under, and if we go with 15.25 we are a penny over.

@chadwhitacre
Copy link
Contributor Author

Is this the only number this happens for, or are there others?

@chadwhitacre
Copy link
Contributor Author

If this is provably the only number this happens for, we can special case it (and good work, @evbogue, for hitting it).

If it's not the only number then (still good work, @evbogue, and) we need a formula for the general case.

@chadwhitacre
Copy link
Contributor Author

Interesting. Could be a rounding error:

$ ./brute.py 
15.54 0.30470588235294117647058824 15.23529411764705882352941176 15.54000000000000000000000000
15.55 0.30490196078431372549019608 15.24509803921568627450980392 15.55000000000000000000000000
15.56 0.30509803921568627450980392 15.25490196078431372549019608 15.56000000000000000000000000
#!/usr/bin/python
from __future__ import division

from decimal import Decimal as D


for i in range(1554, 1557):
    amount = D(str(i / 100))
    fee = amount - (amount / D('1.02'))
    print amount, fee, amount - fee, (amount - fee) * D('1.02') 

@chadwhitacre
Copy link
Contributor Author

That is, we do get from the target back to the target there.

@chadwhitacre
Copy link
Contributor Author

It's related to the quantize call in our rounding.

@chadwhitacre
Copy link
Contributor Author

But even then, can we give PayPal a dollar amount with more than two digits after the decimal point?

@chadwhitacre
Copy link
Contributor Author

No.

screen shot 2013-11-14 at 7 31 52 pm

@chadwhitacre
Copy link
Contributor Author

That was for 15.24509803921568627450980392. How about 15.245?

@chadwhitacre
Copy link
Contributor Author

Nope. Same error. Okay!

@chadwhitacre
Copy link
Contributor Author

Back to square one: is 15.55 the perfect number here?

@chadwhitacre
Copy link
Contributor Author

Many numbers:

$ ./brute.py 
0.25 0.00 0.25 0.26
0.77 0.02 0.75 0.76
1.27 0.02 1.25 1.28
1.79 0.04 1.75 1.78
2.29 0.04 2.25 2.30
2.81 0.06 2.75 2.80
3.31 0.06 3.25 3.32
3.83 0.08 3.75 3.82
4.33 0.08 4.25 4.34
4.85 0.10 4.75 4.84
5.35 0.10 5.25 5.36
5.87 0.12 5.75 5.86
6.37 0.12 6.25 6.38
6.89 0.14 6.75 6.88
7.39 0.14 7.25 7.40
7.91 0.16 7.75 7.90
8.41 0.16 8.25 8.42
8.93 0.18 8.75 8.92
9.43 0.18 9.25 9.44
9.95 0.20 9.75 9.94
10.45 0.20 10.25 10.46
10.97 0.22 10.75 10.96
11.47 0.22 11.25 11.48
11.99 0.24 11.75 11.98
12.49 0.24 12.25 12.50
13.01 0.26 12.75 13.00
13.51 0.26 13.25 13.52
14.03 0.28 13.75 14.02
14.53 0.28 14.25 14.54
15.05 0.30 14.75 15.04
15.55 0.30 15.25 15.56
16.07 0.32 15.75 16.06
16.57 0.32 16.25 16.58
17.09 0.34 16.75 17.08
17.59 0.34 17.25 17.60
18.11 0.36 17.75 18.10
18.61 0.36 18.25 18.62
19.13 0.38 18.75 19.12
19.63 0.38 19.25 19.64
$

That's with:

#!/usr/bin/python
from __future__ import division

from decimal import Decimal as D


def round_(d):
    return d.quantize(D('0.01'))


for i in range(0, 2000):
    amount = D(str(i / 100))
    fee = amount - round_(amount / D('1.02'))
    base = amount - fee
    check = round_(base * D('1.02'))
    if amount == check:
        continue
    print amount, fee, base, check

@chadwhitacre
Copy link
Contributor Author

Look at that! If x % 1 in (0.25, 0.75), we need to ... adjust ... some ... how ...

@chadwhitacre
Copy link
Contributor Author

We can't hit the target. That's the bottom line. I repeat: we can't hit the target.

@chadwhitacre
Copy link
Contributor Author

So what do we do?

@chadwhitacre
Copy link
Contributor Author

Ev has $15.55 to withdraw. We compute $15.25 to pass to PayPal. This results in a 31¢ fee where we intended a 30¢ fee.

Options?

  • We could leave a penny in his Gittip account. Payout based on 15.54. This would be confusing for him if he ever noticed it.

@chadwhitacre
Copy link
Contributor Author

I don't see another way to do it. If we accept the extra penny charge from PayPal then we are leaking escrow, and that's Bad™.

@chadwhitacre
Copy link
Contributor Author

What if we upload the spreadsheet and then take whatever the fee actually is and then as an additional step feed that back into computing the spreadsheet from which we POST exchanges back to Gittip?

The problem is that PayPal calculates fees per-receiver. That still doesn't help us hit the target.

@chadwhitacre
Copy link
Contributor Author

Thanks! :-)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant