Нет описания

gen_report.py 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. from openpyxl import load_workbook, Workbook
  2. from datetime import datetime
  3. from openpyxl.drawing.image import Image
  4. import re
  5. from openpyxl.drawing.spreadsheet_drawing import AbsoluteAnchor
  6. from openpyxl.drawing.xdr import XDRPoint2D, XDRPositiveSize2D
  7. from openpyxl.utils.units import pixels_to_EMU
  8. from openpyxl.utils import get_column_letter
  9. from django.db import models
  10. import os
  11. from django.db.models.fields.files import ImageFieldFile
  12. from pprint import pprint
  13. def center_image_in_cell(ws, cell_address, img_path):
  14. """
  15. Center an image in a specific cell.
  16. Args:
  17. ws: The worksheet object.
  18. cell_address (str): The cell address (e.g., "B2") where the image will be centered.
  19. img_path (str): Path to the image file.
  20. Returns:
  21. None
  22. """
  23. # Load the image
  24. img = Image(img_path)
  25. img.width = img.height = 20
  26. # Get the cell
  27. cell = ws[cell_address]
  28. # Approximate pixel dimensions of the cell
  29. col_letter = get_column_letter(cell.column)
  30. col_width = ws.column_dimensions[col_letter].width or 10 # Default width
  31. row_height = ws.row_dimensions[cell.row].height or 15 # Default height
  32. # Convert dimensions to pixels
  33. col_width_pixels = col_width * 7 # Approximation: 1 Excel unit = ~7 pixels
  34. row_height_pixels = row_height * 0.75 # Approximation: 1 Excel unit = ~0.75 pixels
  35. # Calculate the center position
  36. cell_left = pixels_to_EMU(cell.column - 1) # Column start position in EMU
  37. cell_top = pixels_to_EMU((cell.row - 1) * row_height_pixels) # Row start position in EMU
  38. x_center = cell_left + pixels_to_EMU((col_width_pixels - img.width) / 2)
  39. y_center = cell_top + pixels_to_EMU((row_height_pixels - img.height) / 2)
  40. # Set the image position and size
  41. position = XDRPoint2D(x_center, y_center)
  42. size = XDRPositiveSize2D(pixels_to_EMU(img.width), pixels_to_EMU(img.height))
  43. img.anchor = AbsoluteAnchor(pos=position, ext=size)
  44. # Add the image to the worksheet
  45. ws.add_image(img)
  46. def gen_xlsx(template_file, selected_sheets, prefix_filename, data):
  47. """
  48. Generate an Excel file from a template, fill placeholders, and include only selected sheets.
  49. Args:
  50. template_file (str): Path to the Excel template file.
  51. selected_sheets (list): List of sheet names to include in the output file.
  52. prefix_filename (str): Prefix for the output filename.
  53. data (dict): Data dictionary with sheet-specific keys and fallback keys.
  54. Returns:
  55. str: Path of the generated Excel file.
  56. """
  57. checked_image_path = "/app/report/checkbox_checked.jpg" # Path to the checked checkbox image
  58. unchecked_image_path = "/app/report/checkbox_unchecked.jpg" # Path to the unchecked checkbox image
  59. # Load the template workbook
  60. workbook = load_workbook(template_file)
  61. # Remove sheets not in selected_sheets
  62. for sheet_name in workbook.sheetnames:
  63. if sheet_name not in selected_sheets:
  64. del workbook[sheet_name]
  65. # Process the selected sheets
  66. for sheet_name in selected_sheets:
  67. if sheet_name not in workbook.sheetnames:
  68. raise ValueError(f"Sheet '{sheet_name}' not found in the template.")
  69. sheet = workbook[sheet_name]
  70. # Replace placeholders with actual values
  71. # Handle hiding rows based on patterns in data
  72. for row in sheet.iter_rows():
  73. for cell in row:
  74. if cell.value and isinstance(cell.value, str) and cell.value.startswith("<") and cell.value.endswith(">"):
  75. placeholder = cell.value.strip("<>")
  76. # Determine value priority: `sheet_name.key` > `key`
  77. value = None
  78. sheet_specific_key = f"{sheet_name}.{placeholder}"
  79. if sheet_specific_key in data:
  80. value = data[sheet_specific_key]
  81. elif placeholder in data:
  82. value = data[placeholder]
  83. if value is not None:
  84. if isinstance(value, ImageFieldFile):
  85. pprint("ImageField")
  86. image_path = value.path
  87. if os.path.exists(image_path):
  88. img = Image(image_path)
  89. img.height = 40 # Adjust size as needed
  90. sheet.add_image(img, cell.coordinate)
  91. cell.value = None # Clear placeholder
  92. elif value is True:
  93. img = Image(checked_image_path)
  94. img.width = img.height = 20
  95. print(f"{cell.coordinate}")
  96. sheet.add_image(img, cell.coordinate)
  97. cell.value = None # Remove the placeholder text
  98. elif value is False:
  99. img = Image(unchecked_image_path)
  100. img.width = img.height = 20
  101. sheet.add_image(img, cell.coordinate)
  102. # center_image_in_cell(sheet, cell.coordinate, unchecked_image_path)
  103. cell.value = None # Remove the placeholder text
  104. else:
  105. # Insert the text value directly
  106. cell.value = value
  107. for key, value in data.items():
  108. if isinstance(value, str) and re.match(r"^\d+\[\d+:\d+\]$", value):
  109. # Parse the prefix and row range
  110. prefix, row_range = value.split("[")
  111. row_start, row_end = map(int, row_range[:-1].split(":"))
  112. # Hide rows if the prefix matches the condition
  113. if prefix == "0": # Adjust the condition as needed
  114. sheet.row_dimensions.group(row_start, row_end, hidden=True)
  115. # Generate the output filename with a timestamp
  116. timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
  117. output_path = f"{prefix_filename}_{timestamp}.xlsx"
  118. workbook.save(output_path)
  119. return output_path
  120. if __name__ == "__main__":
  121. # Example usage
  122. data = {
  123. "customer": "Tum Coder",
  124. "inspect_date": "2025-01-15",
  125. "lot_no": "12345",
  126. "staff_name": "Tum 8888",
  127. "man_name": "Tum 999",
  128. "size": "Large",
  129. "pcs": "10 pcs",
  130. "spec": "Spec-A",
  131. "hardness.d1_act": "10",
  132. "hardness.d2_act": "0[24:28]", # Hide rows 24 to 28 if the prefix is "0"
  133. "hardness.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  134. "hardness.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  135. "dimension_app.d1_act": "33",
  136. "dimension_app.d2_act": "0[26:32]", # Hide rows 24 to 28 if the prefix is "0"
  137. "dimension_app.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  138. "dimension_app.spe_acc": True, # Hide rows 24 to 28 if the prefix is "0"
  139. }
  140. output_file = gen_xlsx(
  141. template_file="./hardness.xlsx",
  142. selected_sheets=["hardness", "dimension_app"], # Replace with your actual sheet names
  143. prefix_filename="./output/output",
  144. data=data
  145. )
  146. print(f"Generated file: {output_file}")