diff --git a/oldabe/money_in/__init__.py b/oldabe/money_in/__init__.py index 4ea51cc..0aa1c89 100755 --- a/oldabe/money_in/__init__.py +++ b/oldabe/money_in/__init__.py @@ -30,7 +30,7 @@ from .price import read_price from .equity import write_attributions from .valuation import read_valuation, write_valuation -from .debt import pay_outstanding_debts, create_debts, write_debts +from .debt import pay_outstanding_debts, create_debts, recalculate_debts, write_debts from .advances import draw_down_advances, advance_payments from .equity import handle_investment @@ -137,6 +137,10 @@ def distribute_payment( return processed_debts, debt_payments, transactions, advances +# TODO: the payments within a commit are not ordered. +# It may be better to sort them chronologically, so that +# earlier payments are reflected in attributions before +# later payments are processed. def process_payments(instruments, attributions): """ Process new payments by paying out instruments and then, from the amount @@ -199,9 +203,11 @@ def process_payments(instruments, attributions): valuation = handle_investment( payment, new_itemized_payments, attributions, price, valuation ) + + debts = recalculate_debts(new_debts, new_debt_payments) + return ( - new_debts, - new_debt_payments, + debts, new_transactions, valuation, new_itemized_payments, @@ -221,8 +227,7 @@ def process_payments_and_record_updates(): assert_attributions_normalized(attributions) ( - new_debts, - debt_payments, + debts, transactions, posterior_valuation, new_itemized_payments, @@ -232,9 +237,9 @@ def process_payments_and_record_updates(): # we only write the changes to disk at the end # so that if any errors are encountered, no # changes are made. - write_debts(new_debts, debt_payments) - TransactionsRepo().extend(transactions) + write_debts(debts) write_attributions(attributions) write_valuation(posterior_valuation) + TransactionsRepo().extend(transactions) ItemizedPaymentsRepo().extend(new_itemized_payments) AdvancesRepo().extend(advances) diff --git a/oldabe/money_in/debt.py b/oldabe/money_in/debt.py index ea3bb41..54eec08 100644 --- a/oldabe/money_in/debt.py +++ b/oldabe/money_in/debt.py @@ -12,7 +12,7 @@ from ..models import Payment -def write_debts(new_debts, debt_payments): +def recalculate_debts(new_debts, debt_payments): """ 1. Build a hash of all the processed debts, generating an id for each (based on email and payment file). @@ -22,11 +22,10 @@ def write_debts(new_debts, debt_payments): hash, otherwise write the input version. 4. write the debts that remain in the processed hash. """ - print(new_debts, debt_payments) total_debt_payments = Tally( (dp.debt.key(), dp.amount) for dp in debt_payments ) - replacement = [ + return [ ( dataclasses.replace( debt, @@ -37,11 +36,14 @@ def write_debts(new_debts, debt_payments): ) for debt in [*DebtsRepo(), *new_debts] ] - print(total_debt_payments, list(DebtsRepo()), replacement) + +def write_debts(debts): + """ Write the debts to disk, replacing the existing file. + """ with open(DEBTS_FILE, "w") as f: writer = csv.writer(f) - for debt in replacement: + for debt in debts: writer.writerow(astuple(debt)) diff --git a/tests/integration/old_abe_test.py b/tests/integration/old_abe_test.py index 8626ec0..8df58ef 100644 --- a/tests/integration/old_abe_test.py +++ b/tests/integration/old_abe_test.py @@ -192,6 +192,66 @@ def test_compiled_outstanding_balances(self, mock_git_rev, abe_fs): ) in message +class TestMultiplePayments: + + # TODO: implement me + @time_machine.travel(datetime(1985, 10, 26, 1, 24), tick=False) + @patch('oldabe.models.default_commit_hash', return_value='abcd123') + def test_generates_transactions(self, mock_git_rev, abe_fs): + pass + + @time_machine.travel(datetime(1985, 10, 26, 1, 24), tick=False) + @patch('oldabe.models.default_commit_hash', return_value='abcd123') + def test_dilutes_attributions(self, mock_git_rev, abe_fs): + with localcontext() as context: + context.prec = 2 + amount = 10000 + abe_fs.create_file( + "./abe/payments/1.txt", + contents=f"sam,036eaf6,{amount},1987-06-30 06:25:00", + ) + abe_fs.create_file( + "./abe/payments/2.txt", + contents=f"sam,036eaf6,{amount},1987-06-30 06:24:00", + ) + process_payments_and_record_updates() + with open('./abe/attributions.txt') as f: + assert f.read() == ( + "sid,42\n" "jair,26\n" "ariana,17\n" "sam,16\n" + ) + + # TODO: why do sam and sri not get into attributions when the amount + # is 1000? For higher amounts like 10000 it seems OK + # TODO: add a test to check that, even though both sam and sri get + # attributed equally, sam gets paid from sri's payment, + # but sri doesn't get paid from sam's, assuming sam is first + @time_machine.travel(datetime(1985, 10, 26, 1, 24), tick=False) + @patch('oldabe.models.default_commit_hash', return_value='abcd123') + def test_equal_payment_results_in_equal_share(self, mock_git_rev, abe_fs): + with localcontext() as context: + context.prec = 2 + amount = 10000 + abe_fs.create_file( + "./abe/payments/1.txt", + contents=f"sam,036eaf6,{amount},1987-06-30 06:25:00", + ) + abe_fs.create_file( + "./abe/payments/2.txt", + contents=f"sri,b36eaf6,{amount},1987-06-30 06:24:00", + ) + process_payments_and_record_updates() + with open('./abe/attributions.txt') as f: + assert f.read() == ( + "sid,42\n" "jair,26\n" "ariana,17\n" "sam,7.8\n" "sri,7.8\n" + ) + + # TODO: implement me + @time_machine.travel(datetime(1985, 10, 26, 1, 24), tick=False) + @patch('oldabe.models.default_commit_hash', return_value='abcd123') + def test_compiled_outstanding_balances(self, mock_git_rev, abe_fs): + pass + + class TestUnpayableContributor: def _call(self, abe_fs): diff --git a/tests/unit/money_in_test.py b/tests/unit/advances_test.py similarity index 100% rename from tests/unit/money_in_test.py rename to tests/unit/advances_test.py diff --git a/tests/unit/debt_test.py b/tests/unit/debt_test.py new file mode 100644 index 0000000..cec8fb7 --- /dev/null +++ b/tests/unit/debt_test.py @@ -0,0 +1,10 @@ +from decimal import Decimal + +# See integration tests for now. + + +class TestPlaceholder: + def test_something( + self, + ): + assert True diff --git a/tests/unit/equity_test.py b/tests/unit/equity_test.py new file mode 100644 index 0000000..cec8fb7 --- /dev/null +++ b/tests/unit/equity_test.py @@ -0,0 +1,10 @@ +from decimal import Decimal + +# See integration tests for now. + + +class TestPlaceholder: + def test_something( + self, + ): + assert True diff --git a/tests/unit/price_test.py b/tests/unit/price_test.py new file mode 100644 index 0000000..cec8fb7 --- /dev/null +++ b/tests/unit/price_test.py @@ -0,0 +1,10 @@ +from decimal import Decimal + +# See integration tests for now. + + +class TestPlaceholder: + def test_something( + self, + ): + assert True diff --git a/tests/unit/valuation_test.py b/tests/unit/valuation_test.py new file mode 100644 index 0000000..cec8fb7 --- /dev/null +++ b/tests/unit/valuation_test.py @@ -0,0 +1,10 @@ +from decimal import Decimal + +# See integration tests for now. + + +class TestPlaceholder: + def test_something( + self, + ): + assert True