def test_mismatch_on_evidence(self): """ An otherwise matching Trans. will fail if its evidence is different. """ credit_card_transaction = CreditCardTransactionFactory() amount = Decimal('100') ledger = LedgerFactory() TransactionFactory( UserFactory(), ledger_entries=[ LedgerEntry(amount=debit(amount), ledger=ledger), LedgerEntry(amount=credit(amount), ledger=ledger), ], evidence=[credit_card_transaction], ) ledger_amount_pairs = [ (ledger.name, credit(amount)), (ledger.name, debit(amount)), ] with self.assertRaises(Transaction.DoesNotExist): assert_transaction_in_ledgers_for_amounts_with_evidence( ledger_amount_pairs=ledger_amount_pairs, evidence=[ credit_card_transaction, CreditCardTransactionFactory()], ) with self.assertRaises(Transaction.DoesNotExist): assert_transaction_in_ledgers_for_amounts_with_evidence( ledger_amount_pairs=ledger_amount_pairs, evidence=[], )
def test_multiple_matches(self): """ Multiple matching transactions raises MultipleObjectsReturned. """ credit_card_transaction = CreditCardTransactionFactory() amount = Decimal('100') ledger = LedgerFactory() for _ in range(2): TransactionFactory( UserFactory(), ledger_entries=[ LedgerEntry(amount=debit(amount), ledger=ledger), LedgerEntry(amount=credit(amount), ledger=ledger), ], evidence=[credit_card_transaction], ) self.assertEqual(Transaction.objects.count(), 2) with self.assertRaises(Transaction.MultipleObjectsReturned): assert_transaction_in_ledgers_for_amounts_with_evidence( ledger_amount_pairs=[ (ledger.name, credit(amount)), (ledger.name, debit(amount)), ], evidence=[credit_card_transaction], )
def test_transaction_fields(self): """ Test filtering by `posted_timestamp`, `notes`, `type`, and `user`. """ time = datetime.now() wrong_time = datetime.now() - timedelta(days=1) user1 = UserFactory() user2 = UserFactory() credit_card_transaction = CreditCardTransactionFactory() ttype1 = TransactionTypeFactory(name='1') ttype2 = TransactionTypeFactory(name='2') FIELDS_TO_VALUES = [ ('posted_timestamp', time, wrong_time), ('notes', 'foo', 'bar'), ('type', ttype1, ttype2), ('user', user1, user2), ] for field_name, right_value, wrong_value in FIELDS_TO_VALUES: TransactionFactory( evidence=[credit_card_transaction], **{field_name: right_value}) ledger = Ledger.objects.last() assert_transaction_in_ledgers_for_amounts_with_evidence( ledger_amount_pairs=[ (ledger.name, credit(Decimal('100'))), (ledger.name, debit(Decimal('100'))), ], evidence=[credit_card_transaction], **{field_name: right_value} )
def test_mismatch_on_ledger_entries(self): """ An otherwise matching Trans. will fail if its LedgerEntries mismatch. """ credit_card_transaction = CreditCardTransactionFactory() amount = Decimal('100') ledger = LedgerFactory() evidence = [credit_card_transaction] TransactionFactory( UserFactory(), ledger_entries=[ LedgerEntry(amount=debit(amount), ledger=ledger), LedgerEntry(amount=credit(amount), ledger=ledger), ], evidence=evidence, ) with self.assertRaises(Transaction.DoesNotExist): assert_transaction_in_ledgers_for_amounts_with_evidence( ledger_amount_pairs=[ (ledger.name + 'foo', credit(amount)), (ledger.name + 'foo', debit(amount)), ], evidence=evidence, ) with self.assertRaises(AssertionError): assert_transaction_in_ledgers_for_amounts_with_evidence( ledger_amount_pairs=[ (ledger.name, credit(amount + Decimal('1'))), (ledger.name, debit(amount + Decimal('1'))), ], evidence=evidence, )
def test_custom_evidence(self): ccx = CreditCardTransactionFactory() TransactionFactory(evidence=[ccx]) ledger = Ledger.objects.last() assert_transaction_in_ledgers_for_amounts_with_evidence( ledger_amount_pairs=[ (ledger.name, credit(Decimal('100'))), (ledger.name, debit(Decimal('100'))), ], evidence=[ccx], )
def test_transaction_summary(self): ledger = LedgerFactory() amount = Decimal('500') ccx = CreditCardTransactionFactory() le1 = LedgerEntry(ledger=ledger, amount=credit(amount)) le2 = LedgerEntry(ledger=ledger, amount=debit(amount)) txn = TransactionFactory(evidence=[ccx], ledger_entries=[le1, le2]) self.assertEqual( txn.summary(), { 'entries': [str(entry) for entry in txn.entries.all()], 'related_objects': [ 'TransactionRelatedObject: CreditCardTransaction(id=%s)' % ccx.id, ], }, )
def test_no_matches(self): """ No matching transaction raises DoesNotExist. """ TransactionFactory() credit_card_transaction = CreditCardTransactionFactory() ledger = Ledger.objects.last() self.assertTrue(Transaction.objects.exists()) with self.assertRaises(Transaction.DoesNotExist): assert_transaction_in_ledgers_for_amounts_with_evidence( ledger_amount_pairs=[ (ledger.name, credit(Decimal('100'))), (ledger.name, debit(Decimal('100'))), ], evidence=[credit_card_transaction], )
def setUpTestData(cls): cls.credit_card_transaction = CreditCardTransactionFactory()
def test_using_ledgers_for_reconciliation(self): """ Test ledger behavior with a revenue reconciliation worked example. This test creates an Order and a CreditCardTransaction and, using the four Ledgers created in setUp, it makes all of the ledger entries that an Order and Transaction would be expected to have. There are three, specifically: Revenue Recognition (credit: Revenue, debit:A/R), recording incoming cash (credit: A/R, debit: Cash (unreconciled)) and Reconciliation (credit: Cash (reconciled), debit: Cash (unreconciled)). In table form: Event | Accounts Receivable (unreconciled) | Revenue | Cash (unreconciled) | Cash (reconciled) | Evidence Models ----------------------- | ---------------------------------- | ------- | ------------------- | ----------------- | -------------------------------------------------------------- Test is complete | -$500 | +$500 | | | `Order` Patient pays | +$500 | | -$500 | | `CreditCardTransaction` Payments are reconciled | | | +$500 | -$500 | both `Order` and `CreditCardTransaction` """ # noqa: E501 order = OrderFactory() credit_card_transaction = CreditCardTransactionFactory() # Assert that this Order looks "unrecognized". self.assertEqual( get_balances_for_object(order), {}, ) # Add an entry debiting AR and crediting Revenue: this entry should # reference the Order. create_transaction( self.user, evidence=[order], ledger_entries=[ LedgerEntry( ledger=self.revenue, amount=credit(self.AMOUNT)), LedgerEntry( ledger=self.accounts_receivable, amount=debit(self.AMOUNT)), ], ) # Assert that the correct entries were created. self.assertEqual(LedgerEntry.objects.count(), 2) self.assertEqual(Transaction.objects.count(), 1) # Assert that this Order looks "recognized". self.assertEqual( get_balances_for_object(order), { self.revenue: -self.AMOUNT, self.accounts_receivable: self.AMOUNT, }, ) # Add an entry crediting "A/R" and debiting "Cash (unreconciled)": this # entry should reference the CreditCardTransaction. create_transaction( self.user, evidence=[credit_card_transaction], ledger_entries=[ LedgerEntry( ledger=self.accounts_receivable, amount=credit(self.AMOUNT)), LedgerEntry( ledger=self.cash_unrecon, amount=debit(self.AMOUNT)) ], ) # Assert that the correct entries were created self.assertEqual(LedgerEntry.objects.count(), 4) self.assertEqual(Transaction.objects.count(), 2) # Assert the CreditCardTransaction is in "Cash (unreconciled)". self.assertEqual( get_balances_for_object(credit_card_transaction), { self.accounts_receivable: -self.AMOUNT, self.cash_unrecon: self.AMOUNT, }, ) # Add an entry crediting "Cash (Unreconciled)" and debiting "Cash # (Reconciled)": this entry should reference both an Order and # a CreditCardTransaction. create_transaction( self.user, evidence=[order, credit_card_transaction], ledger_entries=[ LedgerEntry( ledger=self.cash_unrecon, amount=credit(self.AMOUNT)), LedgerEntry( ledger=self.cash_recon, amount=debit(self.AMOUNT)) ], type=self.recon_ttype, ) # Assert that the correct entries were created. self.assertEqual(LedgerEntry.objects.count(), 6) self.assertEqual(Transaction.objects.count(), 3) # Assert that revenue is recognized and reconciled. self.assertEqual( get_balances_for_object(order), { self.accounts_receivable: self.AMOUNT, self.cash_unrecon: -self.AMOUNT, self.cash_recon: self.AMOUNT, self.revenue: -self.AMOUNT, }, )