errands
small jobs the runtime does for the studio.
git clone https://owenrusk.dev/errands.git
errands / tests/test_invoices.py -rw-r--r-- · 3332 bytes
1 import tempfile
2 import unittest
3 from datetime import date
4 from pathlib import Path
5
6 from errands import invoices, mail, settings
7 from errands.mail import Message
8 from tests.fakes import FakeBox, raw
9
10
11 def message(sender="leasing@calderwebb.com", subject="Rent, Unit 4", body="Rent due: $1,875.00\n"):
12 return Message(uid="1", sender=sender, subject=subject, message_id="", references="", body=body)
13
14
15 class ReadTest(unittest.TestCase):
16 def test_a_bill_from_a_payee(self):
17 invoice = invoices.read(message())
18 self.assertEqual(invoice.payee, "Calder & Webb")
19 self.assertEqual(invoice.amount, "1875.00")
20
21 def test_anyone_else_is_just_mail(self):
22 self.assertIsNone(invoices.read(message(sender="someone@example.com")))
23
24 def test_payee_from_settings(self):
25 settings.PAYEES["bills@example.com"] = "Example Utilities"
26 try:
27 self.assertEqual(invoices.read(message(sender="bills@example.com", body="Amount due: $64.12")).payee, "Example Utilities")
28 finally:
29 del settings.PAYEES["bills@example.com"]
30
31 def test_no_amount(self):
32 self.assertIsNone(invoices.read(message(body="the heating is on from monday.\n")))
33
34 def test_due_date(self):
35 invoice = invoices.read(message(body="Rent due: $1,875.00\nDue by: Friday, August 1, 2025\n"))
36 self.assertEqual(invoice.due, "2025-08-01")
37
38
39 class LedgerTest(unittest.TestCase):
40 def setUp(self):
41 self.dir = tempfile.TemporaryDirectory()
42 self.state = settings.STATE
43 self.payments = settings.PAYMENTS
44 settings.STATE = Path(self.dir.name)
45 settings.PAYMENTS = True
46
47 def tearDown(self):
48 settings.STATE = self.state
49 settings.PAYMENTS = self.payments
50 self.dir.cleanup()
51
52 def test_off(self):
53 invoices.record(invoices.read(message()))
54 settings.PAYMENTS = False
55 sent = []
56 self.assertEqual(invoices.pay_due(sent.append), [])
57 with self.assertRaises(RuntimeError):
58 invoices.pay(0, sent.append)
59 self.assertEqual(sent, [])
60
61 def test_from_inbox_records_bills_once(self):
62 inbox = [message(), message(sender="someone@example.com")]
63 self.assertEqual(invoices.from_inbox(lambda: inbox), 1)
64 self.assertEqual(invoices.from_inbox(lambda: inbox), 0)
65 self.assertEqual([i.payee for i in invoices.load()], ["Calder & Webb"])
66
67 def test_from_a_real_message(self):
68 box = FakeBox({b"5": raw(sender="Calder & Webb <leasing@calderwebb.com>", subject="Rent", body="Rent due: $1,875.00\n")})
69 self.assertEqual(invoices.from_inbox(lambda: mail.unread(lambda: box)), 1)
70
71 def test_pay_due_pays_each_once(self):
72 invoices.record(invoices.read(message()))
73 sent = []
74 self.assertEqual(invoices.pay_due(sent.append), [0])
75 self.assertEqual(invoices.pay_due(sent.append), [])
76 self.assertEqual(len(sent), 1)
77 self.assertTrue(invoices.load()[0].paid)
78
79 def test_waits_until_close_to_due(self):
80 invoices.record(invoices.read(message(body="Rent due: $1,875.00\nDue by: August 1, 2025\n")))
81 sent = []
82 self.assertEqual(invoices.pay_due(sent.append, today=date(2025, 7, 20)), [])
83 self.assertEqual(invoices.pay_due(sent.append, today=date(2025, 7, 29)), [0])