Compare commits
2 Commits
b5ddcb76aa
...
da40720a0f
| Author | SHA1 | Date | |
|---|---|---|---|
| da40720a0f | |||
| 948a8e1b75 |
@@ -26,6 +26,13 @@ BORDER = Border(
|
|||||||
top=Side(style="thin", color="D0D7DE"),
|
top=Side(style="thin", color="D0D7DE"),
|
||||||
bottom=Side(style="thin", color="D0D7DE"),
|
bottom=Side(style="thin", color="D0D7DE"),
|
||||||
)
|
)
|
||||||
|
USER_SUMMARY_SEPARATOR_BORDER = Border(
|
||||||
|
left=Side(style="thin", color="D0D7DE"),
|
||||||
|
right=Side(style="thin", color="D0D7DE"),
|
||||||
|
top=Side(style="medium", color="94A3B8"),
|
||||||
|
bottom=Side(style="thin", color="D0D7DE"),
|
||||||
|
)
|
||||||
|
EMPTY_BORDER = Border()
|
||||||
|
|
||||||
|
|
||||||
class BookmarkDocTemplate(SimpleDocTemplate):
|
class BookmarkDocTemplate(SimpleDocTemplate):
|
||||||
@@ -65,6 +72,10 @@ def _autosize_columns(worksheet) -> None:
|
|||||||
worksheet.column_dimensions[get_column_letter(column_index)].width = min(max(width + 4, 12), 30)
|
worksheet.column_dimensions[get_column_letter(column_index)].width = min(max(width + 4, 12), 30)
|
||||||
|
|
||||||
|
|
||||||
|
def _freeze_first_column(worksheet) -> None:
|
||||||
|
worksheet.freeze_panes = "B1"
|
||||||
|
|
||||||
|
|
||||||
def _money_label(locale: ExportLocale, income_totals: list[dict]) -> str:
|
def _money_label(locale: ExportLocale, income_totals: list[dict]) -> str:
|
||||||
return locale.format_money_label(income_totals)
|
return locale.format_money_label(income_totals)
|
||||||
|
|
||||||
@@ -619,6 +630,8 @@ def _append_user_details_block_excel(
|
|||||||
|
|
||||||
|
|
||||||
def _merge_and_style(worksheet, *, row: int, start_col: int, end_col: int, value: str, rtl: bool) -> None:
|
def _merge_and_style(worksheet, *, row: int, start_col: int, end_col: int, value: str, rtl: bool) -> None:
|
||||||
|
if end_col < start_col:
|
||||||
|
end_col = start_col
|
||||||
worksheet.merge_cells(start_row=row, start_column=start_col, end_row=row, end_column=end_col)
|
worksheet.merge_cells(start_row=row, start_column=start_col, end_row=row, end_column=end_col)
|
||||||
cell = worksheet.cell(row=row, column=start_col)
|
cell = worksheet.cell(row=row, column=start_col)
|
||||||
cell.value = value
|
cell.value = value
|
||||||
@@ -628,12 +641,19 @@ def _merge_and_style(worksheet, *, row: int, start_col: int, end_col: int, value
|
|||||||
def _append_merged_heading(worksheet, *, locale: ExportLocale, title: str, span: int) -> int:
|
def _append_merged_heading(worksheet, *, locale: ExportLocale, title: str, span: int) -> int:
|
||||||
worksheet.append([title])
|
worksheet.append([title])
|
||||||
row = worksheet.max_row
|
row = worksheet.max_row
|
||||||
|
span = max(int(span), 1)
|
||||||
if span > 1:
|
if span > 1:
|
||||||
worksheet.merge_cells(start_row=row, start_column=1, end_row=row, end_column=span)
|
worksheet.merge_cells(start_row=row, start_column=1, end_row=row, end_column=span)
|
||||||
_apply_cell_style(worksheet.cell(row=row, column=1), bold=True, fill=HEADER_FILL, rtl=locale.is_rtl)
|
_apply_cell_style(worksheet.cell(row=row, column=1), bold=True, fill=HEADER_FILL, rtl=locale.is_rtl)
|
||||||
return row
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def _clear_excel_cell_style(cell) -> None:
|
||||||
|
cell.value = None
|
||||||
|
cell.fill = PatternFill(fill_type=None)
|
||||||
|
cell.border = EMPTY_BORDER
|
||||||
|
|
||||||
|
|
||||||
def _write_table_row(
|
def _write_table_row(
|
||||||
worksheet,
|
worksheet,
|
||||||
*,
|
*,
|
||||||
@@ -706,6 +726,7 @@ def _render_all_users_overall_excel_sheet(
|
|||||||
) -> None:
|
) -> None:
|
||||||
if locale.is_rtl:
|
if locale.is_rtl:
|
||||||
worksheet.sheet_view.rightToLeft = True
|
worksheet.sheet_view.rightToLeft = True
|
||||||
|
_freeze_first_column(worksheet)
|
||||||
|
|
||||||
scope = report_data["scope"]
|
scope = report_data["scope"]
|
||||||
summary = report_data["summary"]
|
summary = report_data["summary"]
|
||||||
@@ -740,14 +761,10 @@ def _render_all_users_overall_excel_sheet(
|
|||||||
for row_index, values in enumerate(summary_rows, start=10):
|
for row_index, values in enumerate(summary_rows, start=10):
|
||||||
_write_table_row(worksheet, row=row_index, start_col=1, values=values, rtl=locale.is_rtl)
|
_write_table_row(worksheet, row=row_index, start_col=1, values=values, rtl=locale.is_rtl)
|
||||||
|
|
||||||
_merge_and_style(
|
_merge_and_style(worksheet, row=15, start_col=1, end_col=6, value=locale.t("users_summary_sheet"), rtl=locale.is_rtl)
|
||||||
worksheet,
|
_merge_and_style(worksheet, row=15, start_col=8, end_col=10, value=locale.t("clients"), rtl=locale.is_rtl)
|
||||||
row=15,
|
_merge_and_style(worksheet, row=15, start_col=12, end_col=14, value=locale.t("projects"), rtl=locale.is_rtl)
|
||||||
start_col=1,
|
_merge_and_style(worksheet, row=15, start_col=16, end_col=18, value=locale.t("tags"), rtl=locale.is_rtl)
|
||||||
end_col=18,
|
|
||||||
value=locale.t("users_summary_sheet"),
|
|
||||||
rtl=locale.is_rtl,
|
|
||||||
)
|
|
||||||
summary_headers = [
|
summary_headers = [
|
||||||
locale.t("name"),
|
locale.t("name"),
|
||||||
locale.t("mobile"),
|
locale.t("mobile"),
|
||||||
@@ -788,6 +805,10 @@ def _render_all_users_overall_excel_sheet(
|
|||||||
values=values,
|
values=values,
|
||||||
rtl=locale.is_rtl,
|
rtl=locale.is_rtl,
|
||||||
)
|
)
|
||||||
|
if offset == 0:
|
||||||
|
for cell in worksheet[current_row]:
|
||||||
|
if cell.column not in (7, 11, 15):
|
||||||
|
cell.border = USER_SUMMARY_SEPARATOR_BORDER
|
||||||
for column in (1, 2, 3, 6):
|
for column in (1, 2, 3, 6):
|
||||||
_merge_vertical_if_needed(worksheet, start_row=current_row, span=span, column=column)
|
_merge_vertical_if_needed(worksheet, start_row=current_row, span=span, column=column)
|
||||||
rate_rows = user_summary.get("rate_periods") or []
|
rate_rows = user_summary.get("rate_periods") or []
|
||||||
@@ -811,12 +832,9 @@ def _render_all_users_overall_excel_sheet(
|
|||||||
_merge_vertical_if_needed(worksheet, start_row=current_row, span=span, column=18, value_present=True)
|
_merge_vertical_if_needed(worksheet, start_row=current_row, span=span, column=18, value_present=True)
|
||||||
current_row += span
|
current_row += span
|
||||||
|
|
||||||
for row_index in range(16, current_row):
|
for row_index in range(15, current_row):
|
||||||
for column_index in (7, 11, 15):
|
for column_index in (7, 11, 15):
|
||||||
cell = worksheet.cell(row=row_index, column=column_index)
|
_clear_excel_cell_style(worksheet.cell(row=row_index, column=column_index))
|
||||||
cell.value = None
|
|
||||||
cell.fill = PatternFill(fill_type=None)
|
|
||||||
cell.border = Border()
|
|
||||||
|
|
||||||
current_row += 2
|
current_row += 2
|
||||||
for title_key, rows, hour_percentages, income_percentages in (
|
for title_key, rows, hour_percentages, income_percentages in (
|
||||||
@@ -843,7 +861,7 @@ def _render_all_users_overall_excel_sheet(
|
|||||||
worksheet,
|
worksheet,
|
||||||
row=current_row,
|
row=current_row,
|
||||||
start_col=1,
|
start_col=1,
|
||||||
end_col=7,
|
end_col=5,
|
||||||
value=locale.t(title_key),
|
value=locale.t(title_key),
|
||||||
rtl=locale.is_rtl,
|
rtl=locale.is_rtl,
|
||||||
)
|
)
|
||||||
@@ -922,9 +940,7 @@ def _render_excel_sheet(
|
|||||||
) -> None:
|
) -> None:
|
||||||
if locale.is_rtl:
|
if locale.is_rtl:
|
||||||
worksheet.sheet_view.rightToLeft = True
|
worksheet.sheet_view.rightToLeft = True
|
||||||
worksheet.freeze_panes = "E4"
|
_freeze_first_column(worksheet)
|
||||||
else:
|
|
||||||
worksheet.freeze_panes = "A4"
|
|
||||||
_append_meta_block(worksheet, locale=locale, report_data=report_data)
|
_append_meta_block(worksheet, locale=locale, report_data=report_data)
|
||||||
if report_data.get("user_summaries"):
|
if report_data.get("user_summaries"):
|
||||||
worksheet.append([])
|
worksheet.append([])
|
||||||
|
|||||||
@@ -196,10 +196,20 @@ class ReportExporterTests(TestCase):
|
|||||||
summary_sheet = workbook[workbook.sheetnames[0]]
|
summary_sheet = workbook[workbook.sheetnames[0]]
|
||||||
summary_values = list(summary_sheet.iter_rows(values_only=True))
|
summary_values = list(summary_sheet.iter_rows(values_only=True))
|
||||||
|
|
||||||
|
self.assertEqual(summary_sheet.freeze_panes, "B1")
|
||||||
self.assertEqual(summary_sheet["A1"].value, "Workspace Report")
|
self.assertEqual(summary_sheet["A1"].value, "Workspace Report")
|
||||||
self.assertEqual(summary_sheet["B1"].value, "Exports")
|
self.assertEqual(summary_sheet["B1"].value, "Exports")
|
||||||
self.assertEqual(summary_sheet["A15"].value, "Users Summary")
|
self.assertEqual(summary_sheet["A15"].value, "Users Summary")
|
||||||
self.assertIn("A15:R15", {str(item) for item in summary_sheet.merged_cells.ranges})
|
merged_ranges = {str(item) for item in summary_sheet.merged_cells.ranges}
|
||||||
|
self.assertIn("A15:F15", merged_ranges)
|
||||||
|
self.assertIn("H15:J15", merged_ranges)
|
||||||
|
self.assertIn("L15:N15", merged_ranges)
|
||||||
|
self.assertIn("P15:R15", merged_ranges)
|
||||||
|
self.assertNotIn("A15:R15", merged_ranges)
|
||||||
|
self.assertIsNone(summary_sheet["G15"].fill.fill_type)
|
||||||
|
self.assertIsNone(summary_sheet["G16"].fill.fill_type)
|
||||||
|
self.assertIsNone(summary_sheet["K15"].fill.fill_type)
|
||||||
|
self.assertIsNone(summary_sheet["O15"].fill.fill_type)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
tuple(summary_sheet.iter_rows(min_row=16, max_row=16, values_only=True))[0][:18],
|
tuple(summary_sheet.iter_rows(min_row=16, max_row=16, values_only=True))[0][:18],
|
||||||
(
|
(
|
||||||
@@ -226,10 +236,14 @@ class ReportExporterTests(TestCase):
|
|||||||
self.assertTrue(any(row and "Owner User" in row for row in summary_values))
|
self.assertTrue(any(row and "Owner User" in row for row in summary_values))
|
||||||
self.assertTrue(any(row and "09129990001" in row for row in summary_values))
|
self.assertTrue(any(row and "09129990001" in row for row in summary_values))
|
||||||
self.assertTrue(any(row and "Variable rate" in row for row in summary_values))
|
self.assertTrue(any(row and "Variable rate" in row for row in summary_values))
|
||||||
|
self.assertEqual(summary_sheet["A17"].border.top.style, "medium")
|
||||||
|
self.assertEqual(summary_sheet["A18"].border.top.style, "medium")
|
||||||
|
self.assertIsNone(summary_sheet["G17"].border.top)
|
||||||
|
|
||||||
user_sheet = workbook[workbook.sheetnames[1]]
|
user_sheet = workbook[workbook.sheetnames[1]]
|
||||||
user_values = list(user_sheet.iter_rows(values_only=True))
|
user_values = list(user_sheet.iter_rows(values_only=True))
|
||||||
|
|
||||||
|
self.assertEqual(user_sheet.freeze_panes, "B1")
|
||||||
daily_header = next(row[:6] for row in user_values if row and "Date" in row)
|
daily_header = next(row[:6] for row in user_values if row and "Date" in row)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
daily_header,
|
daily_header,
|
||||||
|
|||||||
Reference in New Issue
Block a user