Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions process_report/invoices/pi_specific_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,18 @@ def _get_pi_dataframe(self, data, pi):
if column_name in pi_projects.columns:
column_sums.append(pi_projects[column_name].sum())
sum_columns_list.append(column_name)
pi_projects.loc[len(pi_projects)] = (
None # Adds a new row to end of dataframe initialized with None
)
pi_projects.loc[pi_projects.index[-1], invoice.INVOICE_DATE_FIELD] = "Total"
pi_projects.loc[pi_projects.index[-1], sum_columns_list] = column_sums

# Copy the first row and modify values to keep row formatting
totals_row = pi_projects.iloc[[0]].copy()
# Clear all values to empty strings
for col in totals_row.columns:
totals_row[col] = ""

totals_row[invoice.INVOICE_DATE_FIELD] = "Total"
for col, sum_val in zip(sum_columns_list, column_sums):
totals_row[col] = sum_val

pi_projects = pandas.concat([pi_projects, totals_row], ignore_index=True)

# Add dollar sign to certain columns
for column_name in self.DOLLAR_COLUMN_LIST:
Expand All @@ -106,7 +113,11 @@ def _get_pi_dataframe(self, data, pi):
lambda data: data if pandas.isna(data) else f"${data}"
)

pi_projects.fillna("", inplace=True)
# Convert to StringDtype for template compatibility before filling NA values
pi_projects = pi_projects.astype(pandas.StringDtype())

# Convert any remaining pandas NA values to empty strings for template compatibility
pi_projects = pi_projects.fillna("")

return pi_projects

Expand Down
60 changes: 51 additions & 9 deletions process_report/tests/unit/invoices/test_pi_specific_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,17 @@ def add_dollar_sign(data):
.copy()
.reset_index(drop=True)
)
answer_invoice_pi1.loc[len(answer_invoice_pi1)] = None
answer_invoice_pi1.loc[
answer_invoice_pi1.index[-1], ["Invoice Month", "Balance"]
] = ["Total", 300]
# Create totals row by copying first row and modifying
totals_row = answer_invoice_pi1.iloc[[0]].copy()
for col in totals_row.columns:
totals_row[col] = ""
totals_row["Invoice Month"] = "Total"
totals_row["Balance"] = 300
answer_invoice_pi1 = pandas.concat(
[answer_invoice_pi1, totals_row], ignore_index=True
)

# Apply dollar formatting
for column_name in [
"Prepaid Group Balance",
"Prepaid Group Used",
Expand All @@ -74,17 +81,26 @@ def add_dollar_sign(data):
answer_invoice_pi1[column_name] = answer_invoice_pi1[column_name].apply(
add_dollar_sign
)
answer_invoice_pi1 = answer_invoice_pi1.astype(pandas.StringDtype())
answer_invoice_pi1.fillna("", inplace=True)

answer_invoice_pi2 = (
test_invoice[test_invoice["Manager (PI)"] == "PI2"]
.copy()
.reset_index(drop=True)
)
answer_invoice_pi2.loc[len(answer_invoice_pi2)] = None
answer_invoice_pi2.loc[
answer_invoice_pi2.index[-1], ["Invoice Month", "Balance"]
] = ["Total", 700]

# Create totals row by copying first row and modifying to preserve formatting
totals_row = answer_invoice_pi2.iloc[[0]].copy()
for col in totals_row.columns:
totals_row[col] = ""
totals_row["Invoice Month"] = "Total"
totals_row["Balance"] = 700
answer_invoice_pi2 = pandas.concat(
[answer_invoice_pi2, totals_row], ignore_index=True
)

# Drop prepay columns (they're all NA for PI2)
answer_invoice_pi2 = answer_invoice_pi2.drop(
[
"Prepaid Group Name",
Expand All @@ -97,6 +113,7 @@ def add_dollar_sign(data):
answer_invoice_pi2["Balance"] = answer_invoice_pi2["Balance"].apply(
add_dollar_sign
)
answer_invoice_pi2 = answer_invoice_pi2.astype(pandas.StringDtype())
answer_invoice_pi2.fillna("", inplace=True)

pi_inv = test_utils.new_pi_specific_invoice(data=test_invoice)
Expand Down Expand Up @@ -144,4 +161,29 @@ def test_export_pi(self, mock_subprocess_run, mock_path_exists, mock_filter_cols
f"--print-to-pdf={pi_pdf_path}",
"--no-pdf-header-footer",
]
assert answer_arglist == chrome_arglist[0][:-1]

self.assertEqual(answer_arglist, chrome_arglist[0][:-1])

@mock.patch("process_report.invoices.invoice.Invoice._filter_columns")
@mock.patch("os.path.exists")
@mock.patch("subprocess.run")
def test_process_no_warnings(
self, mock_subprocess_run, mock_path_exists, mock_filter_cols
):
"""Test that no warnings are raised during invoice processing"""
invoice_month = "2024-10"
test_invoice = self._get_test_invoice(
["PI1", "PI1", "PI2", "PI2"],
["BU", "BU", "HU", "HU"],
[100, 200, 300, 400],
group_name=[None, "G1", None, None],
)
with tempfile.TemporaryDirectory() as test_dir:
pi_inv = test_utils.new_pi_specific_invoice(
test_dir, invoice_month, data=test_invoice
)
with self.assertNoLogs(
"process_report.invoices.pi_specific_invoice", level="WARNING"
):
pi_inv.process()
pi_inv.export()