def setUp(self): super(BaseClassIO, self).setUp() self.invoice = Invoice([ TimeEntry(1, _dt(2010, 1, 1), '1st entry', 'Company1', 'job1'), TimeEntry(2.5, _dt(2010, 1, 2), '2nd entry', 'Company1', 'job1') ], _dt(2010, 1, 14), (_dt(2010, 1, 1), _dt(2010, 1, 13)), CompanyJobs('Company1', {'job1': 'Job One'}, 20))
def testSumEntryHours(self): entry1 = TimeEntry(1, None, None, None, None) entry2 = TimeEntry(2, None, None, None, None) entry3 = TimeEntry(2.5, None, None, None, None) entry4 = TimeEntry(3.0, None, None, None, None) _total = TimeEntry.get_hours_total self.assertEqual(_total([entry1, entry2]), 3.0) self.assertEqual(_total([entry1, entry2, entry3]), 5.5) self.assertEqual(_total([entry1, entry2, entry3, entry4]), 8.5)
def testFilterEntries(self): comp1_entries = [ TimeEntry(None, None, None, 'Company1', None) for i in range(100) ] comp2_entries = [ TimeEntry(None, None, None, 'Company2', None) for i in range(100) ] comp3_entries = [ TimeEntry(None, None, None, 'Company3', None) for i in range(100) ] all_entries = comp1_entries + comp2_entries + comp3_entries for entry in TimeEntry.query(all_entries, 'Company1'): self.assertEqual(entry.company, 'Company1') for entry in TimeEntry.query(all_entries, 'Company2'): self.assertEqual(entry.company, 'Company2') for entry in TimeEntry.query(all_entries, 'Company3'): self.assertEqual(entry.company, 'Company3') import random random.shuffle(all_entries) for entry in TimeEntry.query(all_entries, 'Company1'): self.assertEqual(entry.company, 'Company1') for entry in TimeEntry.query(all_entries, 'Company2'): self.assertEqual(entry.company, 'Company2') for entry in TimeEntry.query(all_entries, 'Company3'): self.assertEqual(entry.company, 'Company3')
def testCreateInvoice(self): filtered_entries = TimeEntry.query(self.entries, 'Company1') invoice = Invoice(filtered_entries, None, (None, None), self.company1_jobs) self.assertEqual(invoice.hours_total, 3) filtered_entries = TimeEntry.query(self.entries, 'Company2') invoice = Invoice(filtered_entries, None, (None, None), self.company2_jobs) self.assertEqual(invoice.hours_total, 4.9) filtered_entry_ids = [e.id for e in filtered_entries] self.assertEqual(sorted(invoice.entry_ids), sorted(filtered_entry_ids))
def __init__(self, entries, payment_dt, pay_period, jobs): self.company = jobs.company for i in range(len(entries) - 1, -1, -1): if entries[i].company != self.company: raise ValueError('Entry with different company: %s and %s' % (repr(entries[i]), self.company)) if not entries[i].can_be_invoiced(): del (entries[i]) self.entries = sorted(entries, key=lambda x: x.dt) self.entry_ids = [] self.job_ids = defaultdict(list) for entry in self.entries: self.entry_ids.append(entry.id) self.job_ids[entry.job].append(entry) self.hours_total = TimeEntry.get_hours_total(self.entries) self.invoiced_dt = None self.payment_dt = payment_dt self.paid_dt = None self.sent = False self.payperiod_start = pay_period[0] self.payperiod_end = pay_period[1] self.jobs = jobs self.id = uuid.uuid1().hex
def testSendInvoice(self): """Asserting the invoiced_dt value is weird, like what am I trying to prove? So far, it's only use is being printed in text; of interest for future record keeping? I don't really have a personal need for send(), so it's just this kinda-academic thing I thought an invoice should have. And I think that uncertainty shows in this lame test. """ filtered_entries = TimeEntry.query(self.entries, 'Company1') invoice = Invoice(filtered_entries, None, (None, None), self.company1_jobs) send_start = _dt.now() invoice.send() send_end = _dt.now() self.assertLess(send_start, invoice.invoiced_dt) self.assertGreater(send_end, invoice.invoiced_dt) for entry in invoice.entries: self.assertFalse(entry.can_be_invoiced()) self.assertEqual(entry.invoiced_dt, invoice.invoiced_dt) self.assertTrue(invoice.sent)
def testOpenEntry(self): entry = TimeEntry(1, _dt(2010, 1, 1), '1st entry', 'Company1', 'job1') entry_path = io_txt.get_entry_path(entry) io_txt.write_entry(entry) read_entry = io_txt.open_entry(entry_path) self.assertEqual(read_entry.id, entry.id) del_path(entry_path)
def testCreateTimeEntry(self): entry = TimeEntry(1, _dt(2010,1,1), '1st entry', 'Company1', 'job1') self.assertEqual(entry.hours, 1.0) self.assertEqual(entry.dt, _dt(2010,1,1)) self.assertEqual(entry.message, '1st entry') self.assertEqual(entry.company, 'Company1') self.assertEqual(entry.job, 'job1')
def testWriteReport(self): self.invoice.send() report_path = io_txt.get_report_path(self.invoice) io_txt.write_report(self.invoice) with open(report_path, 'r') as f: written_txt = f.read() _entries = self.invoice.entries self.assertIn(_entries[0].message, written_txt) self.assertIn(str(TimeEntry.get_hours_total(_entries)), written_txt) del_path(report_path)
def testIdCollisions(self): """Using something other than self(id), right now uuid1(). I was using self.id = id(self) for ID, which would make for a collison in about 10 iterations of the following loop. Noticed this problem as an intermittent already-exists-error in: test_io:TestGenInvoice.testRealRun() """ ids = [] for i in range(100): invoice = Invoice( [ TimeEntry(1, _dt(2010,1,1), '1st entry', 'Company1', 'job1'), TimeEntry(2.5, _dt(2010,1,2), '2nd entry', 'Company1', 'job1') ], _dt(2010,1,14), (_dt(2010,1,1), _dt(2010,1,13)), CompanyJobs('Company1', {'job1': 'Job One'}, 20) ) self.assertNotIn(invoice.id, ids) ids.append(invoice.id)
def testFilterEntriesByDate(self): e1 = TimeEntry(1, _dt(2010,1,1), '1st entry', 'Company1', 'job1') e2 = TimeEntry(1, _dt(2010,1,2), '2nd entry', 'Company1', 'job1') e3 = TimeEntry(1, _dt(2010,1,3), '3rd entry', 'Company1', 'job1') self.assertEqual( TimeEntry.filter_by_date([e1], _dt(2010,1,1), _dt(2010,1,1)), [e1] ) self.assertEqual( TimeEntry.filter_by_date([e1, e2, e3], _dt(2010,1,1), _dt(2010,1,1)), [e1] ) # With date range in February, all January entries are filtered out self.assertEqual( TimeEntry.filter_by_date([e1, e2, e3], _dt(2010,2,1), _dt(2010,2,3)), [] )
def parse_entries_from_note(note_data, jobs): from time_entry import TimeEntry def _assert_field_count(row, field_count): assert len(row) == field_count, \ 'Expected %s field(s) in row, got %d: %s' % (field_count, len(row), row) def cast_date(s): if not s: return None mo, day, yr = map(int, s.split('/')) return datetime.datetime(2000 + yr, mo, day) def cast_float(s): if not s: return None return float(s) def cast_int(s): if not s: return None return int(s) def _unicode(s): if not s: return None return unicode(s, 'utf-8') def _job_id(s): if not s: return None id_or_name = _unicode(s) if jobs.get_name_by_id(id_or_name): return id_or_name job_id = jobs.get_id_by_name(id_or_name) if job_id: return job_id return None import csv import datetime if not note_data.read().strip(): raise ValueError('no data in note_data') note_data.seek(0) note_data = replace_in_file(note_data) reader = csv.reader(note_data, delimiter=',', quotechar='"') entries = [] for row in reader: if not row: continue _assert_field_count(row, 5) entries.append( TimeEntry(cast_float(row[0]), cast_date(row[1]), _unicode(row[2]), _unicode(row[3]), _job_id(row[4]))) return entries