Skip to content

Commit eda5ed1

Browse files
committed
fix: generating invoice numbers
1 parent c5f2d72 commit eda5ed1

File tree

4 files changed

+30
-56
lines changed

4 files changed

+30
-56
lines changed

app/invoicing/data_source.py

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import datetime
44

55
from loguru import logger
6+
import sqlmodel
67

78
from core.abstractions import SQLModelDataSourceMixin
89
from core.intent_result import IntentResult
@@ -81,33 +82,6 @@ def save_timesheet(self, timesheet: Timesheet):
8182
"""Creates or updates a timesheet"""
8283
self.store(timesheet)
8384

84-
def get_last_invoice(self) -> IntentResult[Invoice]:
85-
"""Get the last invoice.
86-
87-
Returns:
88-
IntentResult:
89-
was_intent_successful : bool
90-
data : Invoice
91-
log_message : str if an error or exception occurs
92-
exception : Exception if an exception occurs
93-
"""
94-
try:
95-
# query the database to get the Invoice that was last added
96-
with self.create_session() as session:
97-
last_invoice = (
98-
session.query(Invoice).order_by(Invoice.id.desc()).first()
99-
)
100-
return IntentResult(
101-
was_intent_successful=True,
102-
data=last_invoice,
103-
)
104-
except Exception as e:
105-
return IntentResult(
106-
was_intent_successful=False,
107-
log_message=f"Exception raised @InvoicingDataSource.get_last_invoice_number {e.__class__.__name__}",
108-
exception=e,
109-
)
110-
11185
def get_timesheet_for_invoice(self, invoice: Invoice) -> Timesheet:
11286
"""Get the timesheet associated with an invoice
11387
@@ -127,3 +101,22 @@ def get_timesheet_for_invoice(self, invoice: Invoice) -> Timesheet:
127101
)
128102
timesheet = invoice.timesheets[0]
129103
return timesheet
104+
105+
def generate_invoice_number(self, date: datetime.date) -> str:
106+
"""Generate a new valid invoice number"""
107+
# invoice number scheme: YYYY-MM-DD-XX
108+
prefix = date.strftime("%Y-%m-%d")
109+
110+
# where XX is the number of invoices for the day
111+
# if there are no invoices for the day, start at 1
112+
# if there are invoices for the day, start at the last invoice number + 1
113+
# count the number of invoices for the day
114+
with self.create_session() as session:
115+
invoices = session.exec(
116+
sqlmodel.select(Invoice).where(Invoice.date == date)
117+
).all()
118+
invoice_count = len(invoices)
119+
if invoice_count == 0:
120+
return f"{prefix}-01"
121+
else:
122+
return f"{prefix}-{invoice_count + 1}"

app/invoicing/intent.py

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,18 @@ def create_invoice(
108108
to_date,
109109
)
110110

111+
invoice_number = self._invoicing_data_source.generate_invoice_number(
112+
invoice_date
113+
)
114+
111115
invoice: Invoice = invoicing.generate_invoice(
116+
date=invoice_date,
117+
number=invoice_number,
112118
timesheets=[
113119
timesheet,
114120
],
115121
contract=project.contract,
116122
project=project,
117-
date=invoice_date,
118123
)
119124

120125
if render:
@@ -363,30 +368,6 @@ def view_timesheet_for_invoice(self, invoice: Invoice) -> IntentResult[None]:
363368
error_msg=error_message,
364369
)
365370

366-
def generate_invoice_number(
367-
self,
368-
invoice_date: Optional[date] = None,
369-
) -> IntentResult[str]:
370-
"""Creates a unique invoice number"""
371-
# get the number of the most recent invoice
372-
result: IntentResult[Invoice] = self._invoicing_data_source.get_last_invoice()
373-
if result.was_intent_successful:
374-
last_invoice: Invoice = result.data
375-
last_invoice_number: str = last_invoice.invoice_number
376-
# increment the invoice number
377-
invoice_number = last_invoice_number + 1
378-
return IntentResult(
379-
was_intent_successful=True,
380-
data=f"{invoice_number:05d}",
381-
)
382-
else:
383-
# create the first invoice number
384-
invoice_number = 1
385-
return IntentResult(
386-
was_intent_successful=True,
387-
data=f"{invoice_number:05d}",
388-
)
389-
390371
def get_time_tracking_data_as_dataframe(self) -> Optional[DataFrame]:
391372

392373
result = self._timetracking_intent.get_timetracking_data()

tuttle/invoicing.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ def generate_invoice(
1717
timesheets: List[Timesheet],
1818
contract: Contract,
1919
project: Project,
20+
number: str,
2021
date: datetime.date = datetime.date.today(),
21-
counter: int = None,
2222
) -> Invoice:
2323
invoice = Invoice(
2424
date=date,
2525
contract=contract,
2626
project=project,
27+
number=number,
2728
)
2829
for timesheet in timesheets:
2930
total_hours = timesheet.total / pandas.Timedelta("1h")
@@ -38,8 +39,6 @@ def generate_invoice(
3839
description=timesheet.title,
3940
)
4041

41-
# TODO: replace with auto-incrementing numbers
42-
invoice.generate_number(counter=counter)
4342
return invoice
4443

4544

tuttle_tests/test_invoice.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def test_generate_invoice(
4848
demo_projects,
4949
demo_calendar_timetracking,
5050
):
51-
for project in demo_projects:
51+
for i, project in enumerate(demo_projects):
5252
timesheets = []
5353
for period in ["January 2022", "February 2022"]:
5454
(period_start, period_end) = get_month_start_end(period)
@@ -66,5 +66,6 @@ def test_generate_invoice(
6666
contract=project.contract,
6767
project=project,
6868
date=datetime.date.today(),
69+
number=f"{datetime.date.today().strftime('%Y-%m-%d')}-{i}",
6970
)
7071
# assert invoice.total > 0

0 commit comments

Comments
 (0)