tum il y a 11 mois
Parent
commit
811230361d

+ 2 - 0
Dockerfile

1
 # Use Python 3.10-slim as a base
1
 # Use Python 3.10-slim as a base
2
 FROM python:3.10-slim
2
 FROM python:3.10-slim
3
+ENV PYTHONUNBUFFERED=1
4
+
3
 
5
 
4
 # Install system dependencies for MS SQL ODBC (comment out if not using MSSQL)
6
 # Install system dependencies for MS SQL ODBC (comment out if not using MSSQL)
5
 # Install system dependencies for MS SQL ODBC and command-line tools
7
 # Install system dependencies for MS SQL ODBC and command-line tools

+ 1 - 1
app/legacy/templates/legacy/datacrud_list.html

30
     <thead>
30
     <thead>
31
         <tr class="bg-gray-100 text-left text-sm uppercase">
31
         <tr class="bg-gray-100 text-left text-sm uppercase">
32
             {% for field in fields %}
32
             {% for field in fields %}
33
-                <th class="border border-gray-200 px-4 py-2 text-left">{{ field.verbose_name }}</th>
33
+            <th class="border border-gray-200 px-4 py-2 text-left">{% firstof field.verbose_name field.name %} </th>
34
             {% endfor %}
34
             {% endfor %}
35
             <th class="py-2 px-4 border-b">Actions</th>
35
             <th class="py-2 px-4 border-b">Actions</th>
36
         </tr>
36
         </tr>

BIN
app/report/coi_templates.xlsx


+ 143 - 43
app/report/gen_report.py

7
 from openpyxl.drawing.spreadsheet_drawing import AbsoluteAnchor
7
 from openpyxl.drawing.spreadsheet_drawing import AbsoluteAnchor
8
 from openpyxl.drawing.xdr import XDRPoint2D, XDRPositiveSize2D
8
 from openpyxl.drawing.xdr import XDRPoint2D, XDRPositiveSize2D
9
 from openpyxl.utils.units import pixels_to_EMU
9
 from openpyxl.utils.units import pixels_to_EMU
10
-from openpyxl.utils import get_column_letter
10
+from openpyxl.utils import get_column_letter, column_index_from_string
11
 from django.db import models
11
 from django.db import models
12
 import os
12
 import os
13
 from django.db.models.fields.files import ImageFieldFile
13
 from django.db.models.fields.files import ImageFieldFile
14
 from pprint import pprint
14
 from pprint import pprint
15
+from PIL import Image as PILImage
16
+from openpyxl.drawing.xdr import XDRPoint2D, XDRPositiveSize2D
17
+from openpyxl.utils.units import pixels_to_EMU
18
+from openpyxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor
19
+
15
 
20
 
16
-def center_image_in_cell(ws, cell_address, img_path):
21
+def set_image_with_offset_old(sheet, img, cell_coordinate, offset_x=0, offset_y=0):
17
     """
22
     """
18
-    Center an image in a specific cell.
23
+    Add an image to the sheet with an offset relative to the top-left corner of a cell.
19
 
24
 
20
-    Args:
21
-        ws: The worksheet object.
22
-        cell_address (str): The cell address (e.g., "B2") where the image will be centered.
23
-        img_path (str): Path to the image file.
25
+    :param sheet: The worksheet
26
+    :param img: The openpyxl Image object
27
+    :param cell_coordinate: Cell to place the image (e.g., "B2")
28
+    :param offset_x: Horizontal offset in pixels
29
+    :param offset_y: Vertical offset in pixels
30
+    """
31
+    col_letter = ''.join(filter(str.isalpha, cell_coordinate))  # Extract column letter
32
+    row_number = int(''.join(filter(str.isdigit, cell_coordinate)))  # Extract row number
24
 
33
 
25
-    Returns:
26
-        None
34
+    # Get column width and row height in pixels
35
+    col_width = sheet.column_dimensions[get_column_letter(column_index_from_string(col_letter))].width or 10
36
+    row_height = sheet.row_dimensions[row_number].height or 15
37
+
38
+    # Approximate conversion of Excel units to pixels
39
+    col_pixels = col_width * 7.5  # Excel's ~7.5 pixels per width unit
40
+    row_pixels = row_height * 0.75  # Approximation for row height in pixels
41
+
42
+    # Calculate absolute positions based on offsets
43
+    anchor_x = col_pixels + offset_x
44
+    anchor_y = row_pixels + offset_y
45
+
46
+    # Set the anchor for the image
47
+    img.anchor = cell_coordinate
48
+    img.anchor.dx = int(anchor_x * 9525)  # Convert to EMUs (Excel Measurement Units)
49
+    img.anchor.dy = int(anchor_y * 9525)  # Convert to EMUs (Excel Measurement Units)
50
+
51
+    sheet.add_image(img)
52
+
53
+
54
+def set_image_with_offset(sheet, img, cell_coordinate, offset_x=0, offset_y=0):
27
     """
55
     """
28
-    # Load the image
29
-    img = Image(img_path)
30
-    img.width = img.height = 20
31
-
32
-    # Get the cell
33
-    cell = ws[cell_address]
34
-
35
-    # Approximate pixel dimensions of the cell
36
-    col_letter = get_column_letter(cell.column)
37
-    col_width = ws.column_dimensions[col_letter].width or 10  # Default width
38
-    row_height = ws.row_dimensions[cell.row].height or 15  # Default height
39
-
40
-    # Convert dimensions to pixels
41
-    col_width_pixels = col_width * 7  # Approximation: 1 Excel unit = ~7 pixels
42
-    row_height_pixels = row_height * 0.75  # Approximation: 1 Excel unit = ~0.75 pixels
43
-
44
-    # Calculate the center position
45
-    cell_left = pixels_to_EMU(cell.column - 1)  # Column start position in EMU
46
-    cell_top = pixels_to_EMU((cell.row - 1) * row_height_pixels)  # Row start position in EMU
47
-    x_center = cell_left + pixels_to_EMU((col_width_pixels - img.width) / 2)
48
-    y_center = cell_top + pixels_to_EMU((row_height_pixels - img.height) / 2)
49
-
50
-    # Set the image position and size
51
-    position = XDRPoint2D(x_center, y_center)
56
+    Add an image to the sheet with an offset relative to the top-left corner of a cell.
57
+
58
+    :param sheet: The worksheet
59
+    :param img: The openpyxl Image object
60
+    :param cell_coordinate: Cell to place the image (e.g., "B2")
61
+    :param offset_x: Horizontal offset in pixels
62
+    :param offset_y: Vertical offset in pixels
63
+    """
64
+    # Extract the column and row from the cell coordinate
65
+    col_letter = ''.join(filter(str.isalpha, cell_coordinate))  # Extract column letter
66
+    row_number = int(''.join(filter(str.isdigit, cell_coordinate)))  # Extract row number
67
+
68
+    # Get the zero-based indices for the cell
69
+    col_idx = column_index_from_string(col_letter) - 1
70
+    row_idx = row_number - 1
71
+
72
+    # Approximate column width and row height to pixels
73
+    col_width = sheet.column_dimensions[col_letter].width or 10  # Default column width
74
+    row_height = sheet.row_dimensions[row_number].height or 15  # Default row height
75
+
76
+    # Convert column width and row height to pixels
77
+    col_pixels = col_width * 7.5  # Approximation: ~7.5 pixels per width unit
78
+    row_pixels = row_height * 0.75  # Approximation: ~0.75 pixels per height unit
79
+
80
+    # Calculate the position in pixels for the top-left corner of the cell
81
+    cell_x = col_idx * col_pixels
82
+    cell_y = row_idx * row_pixels
83
+
84
+    # Apply the offsets
85
+    final_x = cell_x + offset_x
86
+    final_y = cell_y + offset_y
87
+
88
+    # Convert to EMUs
89
+    pos = XDRPoint2D(pixels_to_EMU(final_x), pixels_to_EMU(final_y))
52
     size = XDRPositiveSize2D(pixels_to_EMU(img.width), pixels_to_EMU(img.height))
90
     size = XDRPositiveSize2D(pixels_to_EMU(img.width), pixels_to_EMU(img.height))
53
-    img.anchor = AbsoluteAnchor(pos=position, ext=size)
91
+
92
+    # Set the image's anchor with the position and size
93
+    img.anchor = AbsoluteAnchor(pos=pos, ext=size)
54
 
94
 
55
     # Add the image to the worksheet
95
     # Add the image to the worksheet
56
-    ws.add_image(img)
96
+    sheet.add_image(img)
97
+
98
+
99
+
100
+def center_image_in_cell(sheet, img, cell_coordinate):
101
+    """
102
+    Center an image inside a specified cell.
103
+
104
+    :param sheet: The worksheet
105
+    :param img: The openpyxl Image object
106
+    :param cell_coordinate: The cell to center the image in (e.g., "C3")
107
+    """
108
+    # Extract column and row from the cell coordinate
109
+    col_letter = ''.join(filter(str.isalpha, cell_coordinate))  # Extract column letter
110
+    row_number = int(''.join(filter(str.isdigit, cell_coordinate)))  # Extract row number
111
+    col_idx = column_index_from_string(col_letter) - 1  # Convert to zero-based column index
112
+
113
+    # Get cell dimensions
114
+    col_width = sheet.column_dimensions[col_letter].width or 10  # Default width if not set
115
+    row_height = sheet.row_dimensions[row_number].height or 15  # Default height if not set
116
+
117
+    # Convert dimensions to pixels (approximation)
118
+    col_pixels = col_width * 7.5  # 1 Excel column width unit ≈ 7.5 pixels
119
+    row_pixels = row_height * 0.75  # 1 Excel row height unit ≈ 0.75 pixels
120
+
121
+    # Get image dimensions
122
+    img_width, img_height = img.width, img.height
123
+
124
+    # Calculate offsets to center the image
125
+    offset_x = int((col_pixels - img_width) / 2 * pixels_to_EMU(1))  # Center horizontally
126
+    offset_y = int((row_pixels - img_height) / 2 * pixels_to_EMU(1))  # Center vertically
127
+
128
+    # Define the anchor for the image
129
+    _from = AnchorMarker(col=col_idx, row=row_number - 1, colOff=offset_x, rowOff=offset_y)
130
+    to = AnchorMarker(col=col_idx + 1, row=row_number, colOff=-offset_x, rowOff=-offset_y)
131
+
132
+    # Use TwoCellAnchor for positioning
133
+    img.anchor = TwoCellAnchor(editAs="oneCell", _from=_from, to=to)
134
+
135
+    # Add the image to the sheet
136
+    sheet.add_image(img)
57
 
137
 
58
 
138
 
59
 def gen_xlsx(template_file, selected_sheets, prefix_filename, data):
139
 def gen_xlsx(template_file, selected_sheets, prefix_filename, data):
89
 
169
 
90
         # Replace placeholders with actual values
170
         # Replace placeholders with actual values
91
         # Handle hiding rows based on patterns in data
171
         # Handle hiding rows based on patterns in data
92
-        
172
+         
93
         for row in sheet.iter_rows():
173
         for row in sheet.iter_rows():
94
             for cell in row:
174
             for cell in row:
95
                 if cell.value and isinstance(cell.value, str) and cell.value.startswith("<") and cell.value.endswith(">"):
175
                 if cell.value and isinstance(cell.value, str) and cell.value.startswith("<") and cell.value.endswith(">"):
108
                             pprint("ImageField")
188
                             pprint("ImageField")
109
                             image_path = value.path
189
                             image_path = value.path
110
                             if os.path.exists(image_path):
190
                             if os.path.exists(image_path):
191
+                                # img = Image(image_path)
192
+                                # img.height = 40  # Adjust size as needed
193
+                                pil_img = PILImage.open(image_path)
194
+                                original_width, original_height = pil_img.size
195
+
196
+                                # Desired height (e.g., 40), calculate the new width to maintain aspect ratio
197
+                                desired_height = 40
198
+                                aspect_ratio = original_width / original_height
199
+                                new_width = int(desired_height * aspect_ratio)
200
+
201
+                                # Resize the image using Pillow (optional, for saving memory during export)
202
+                                resized_img = pil_img.resize((new_width, desired_height), PILImage.Resampling.LANCZOS)
203
+                                resized_img.save(image_path)  # Save the resized image back to the same path
204
+
205
+                                # Insert the resized image into the Excel sheet
111
                                 img = Image(image_path)
206
                                 img = Image(image_path)
112
-                                img.height = 40  # Adjust size as needed
113
-                                sheet.add_image(img, cell.coordinate)
207
+                                img.width, img.height = new_width, desired_height  # Set the dimensions
208
+                                # sheet.add_image(img, cell.coordinate)
209
+                                center_image_in_cell(sheet, img, cell.coordinate, )
114
                                 cell.value = None  # Clear placeholder
210
                                 cell.value = None  # Clear placeholder
211
+
115
                         elif value is True:
212
                         elif value is True:
116
                             img = Image(checked_image_path)
213
                             img = Image(checked_image_path)
117
-                            img.width = img.height = 20
214
+                            img.width = img.height = 10
118
                             print(f"{cell.coordinate}")
215
                             print(f"{cell.coordinate}")
119
-                            sheet.add_image(img, cell.coordinate)
216
+                            # sheet.add_image(img, cell.coordinate)
217
+                            # set_image_with_offset(sheet, img, cell.coordinate, offset_x=100)
218
+                            center_image_in_cell(sheet,img, cell.coordinate, )
120
                             cell.value = None  # Remove the placeholder text
219
                             cell.value = None  # Remove the placeholder text
121
                         elif value is False:
220
                         elif value is False:
122
                             img = Image(unchecked_image_path)
221
                             img = Image(unchecked_image_path)
123
-                            img.width = img.height = 20
124
-                            sheet.add_image(img, cell.coordinate)
125
-                            # center_image_in_cell(sheet, cell.coordinate, unchecked_image_path)
222
+                            img.width = img.height = 10
223
+                            # sheet.add_image(img, cell.coordinate)
224
+                            # set_image_with_offset(sheet, img, cell.coordinate, offset_x=100)
225
+                            center_image_in_cell(sheet, img, cell.coordinate, )
126
                             cell.value = None  # Remove the placeholder text
226
                             cell.value = None  # Remove the placeholder text
127
                         else:
227
                         else:
128
                             # Insert the text value directly
228
                             # Insert the text value directly

+ 8 - 8
app/report/templates/report/coi.html

8
   <h1 class="text-2xl font-bold text-gray-800">Export Center</h1>
8
   <h1 class="text-2xl font-bold text-gray-800">Export Center</h1>
9
   <form method='post'>
9
   <form method='post'>
10
     {% csrf_token %}
10
     {% csrf_token %}
11
-    <div class="flex items-center justify-between mb-4">
12
-      <h1 class="text-lg font-bold text-gray-800">TKX Certificate Issue</h1>
13
-      <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded hover:bg-gray-400">
14
-        รายละเอียด CheckedBy|ApproveBy
15
-      </button>
16
-    </div>
17
     <div class="flex items-center gap-2 mb-4">
11
     <div class="flex items-center gap-2 mb-4">
18
       <label for="lot-number" class="text-gray-700 font-medium">Lot No. :</label>
12
       <label for="lot-number" class="text-gray-700 font-medium">Lot No. :</label>
19
       <input id="lot-number" type="text" class="border border-gray-300 rounded px-4 py-2 focus:outline-blue-500" placeholder="Enter Lot No." name='lot_no' required x-model="lot_no">
13
       <input id="lot-number" type="text" class="border border-gray-300 rounded px-4 py-2 focus:outline-blue-500" placeholder="Enter Lot No." name='lot_no' required x-model="lot_no">
35
         <div class="grid grid-cols-2 gap-4">
29
         <div class="grid grid-cols-2 gap-4">
36
           <div class="my-4">
30
           <div class="my-4">
37
             <label for="qa1" class="block mb-2 text-sm font-medium text-gray-900">Select QA.1</label>
31
             <label for="qa1" class="block mb-2 text-sm font-medium text-gray-900">Select QA.1</label>
38
-            <select id="qa1" name="qa1" class="block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
32
+            <select id="qa1" name="qa1" class="block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500" x-model='qa1'>
39
               <option value="" disabled selected>Choose a user</option>
33
               <option value="" disabled selected>Choose a user</option>
40
               {% for user in users %}
34
               {% for user in users %}
41
               <option value="{{ user.id }}">{{ user.profile }}</option>
35
               <option value="{{ user.id }}">{{ user.profile }}</option>
44
           </div>
38
           </div>
45
           <div class="my-4">
39
           <div class="my-4">
46
             <label for="qa2" class="block mb-2 text-sm font-medium text-gray-900">Select QA.2</label>
40
             <label for="qa2" class="block mb-2 text-sm font-medium text-gray-900">Select QA.2</label>
47
-            <select id="qa2" name="qa2" class="block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
41
+            <select id="qa2" name="qa2" class="block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500" x-model='qa2'>
48
               <option value="" disabled selected>Choose a user</option>
42
               <option value="" disabled selected>Choose a user</option>
49
               {% for user in users %}
43
               {% for user in users %}
50
               <option value="{{ user.id }}">{{ user.profile }}</option>
44
               <option value="{{ user.id }}">{{ user.profile }}</option>
139
     return {
133
     return {
140
       lot_no: '', // Bind this to the input value
134
       lot_no: '', // Bind this to the input value
141
       exports: [],
135
       exports: [],
136
+      qa1: null,
137
+      qa2: null,
142
       gen_report_url: '{% url "report:gen_report" %}', 
138
       gen_report_url: '{% url "report:gen_report" %}', 
143
       downloadUrl: null, // Stores the download link after export success
139
       downloadUrl: null, // Stores the download link after export success
144
       init() {
140
       init() {
145
         //alert("COI Report");
141
         //alert("COI Report");
142
+        this.qa1 = '';
143
+        this.qa2 = '';
146
       },
144
       },
147
       async exportCOI() {
145
       async exportCOI() {
148
               if (!this.lot_no) {
146
               if (!this.lot_no) {
155
                   const response = await axios.post(this.gen_report_url, {
153
                   const response = await axios.post(this.gen_report_url, {
156
                       lot_no: this.lot_no,
154
                       lot_no: this.lot_no,
157
                       exports: this.exports,
155
                       exports: this.exports,
156
+                      qa1: this.qa1,
157
+                      qa2: this.qa2
158
                   });
158
                   });
159
 
159
 
160
                   if (response.status === 200) {
160
                   if (response.status === 200) {

+ 91 - 16
app/report/views.py

16
 import json
16
 import json
17
 from django.contrib.auth.decorators import login_required
17
 from django.contrib.auth.decorators import login_required
18
 from django.contrib.auth.models import User
18
 from django.contrib.auth.models import User
19
+from legacy.models import Data
19
 
20
 
20
 
21
 
21
 def index(request):
22
 def index(request):
67
     # config_edit_fields = ["lot_no", "code"]
68
     # config_edit_fields = ["lot_no", "code"]
68
     ordering = ["-created_at", "-id",]
69
     ordering = ["-created_at", "-id",]
69
 
70
 
70
-def create_coi_file(lot_no, sheets, user):
71
+def convert_sheet_data(sheet_data):
72
+    """
73
+    Convert sheet_data to the required form with prefixed keys.
74
+    
75
+    :param sheet_data: Dictionary with sheet names as keys and their data as values.
76
+    :return: Dictionary in the required key-value format.
77
+    """
78
+    converted_data = {}
79
+
80
+    for sheet_name, data in sheet_data.items():
81
+        for key, value in data.items():
82
+            # Prefix each key with the sheet name
83
+            converted_key = f"{sheet_name}.{key}"
84
+            converted_data[converted_key] = value
85
+
86
+    return converted_data
87
+
88
+def generate_hardness_out_values(lot_no):
89
+    """
90
+    Generate a dictionary of placeholder values for a given lot_no.
91
+
92
+    :param lot_no: The lot number to query data for.
93
+    :return: A dictionary with placeholders (e.g., v1_1, v1_2, ...) as keys and their respective values.
94
+    """
95
+    # Query the Data model for records matching the given lot_no
96
+    records = Data.objects.filter(lot_no=lot_no).order_by('row_no')
97
+    print(f"records {lot_no} = {records.values()}")
98
+    # Initialize an empty dictionary to store placeholder values
99
+    placeholders = {}
100
+
101
+    # Iterate over the records to populate placeholder values
102
+    for record_idx, record in enumerate(records, start=1):
103
+        placeholders[f'v{record_idx}_1'] = record.p1  # Checkpoint 1 value
104
+        placeholders[f'v{record_idx}_2'] = record.p2  # Checkpoint 2 value
105
+        placeholders[f'v{record_idx}_3'] = record.p3  # Checkpoint 3 value
106
+        placeholders[f'v{record_idx}_4'] = record.avg  # Average value
107
+        placeholders[f'v{record_idx}_5'] = record.rgrade  # Judgment value
108
+
109
+    return placeholders
110
+
111
+def merge_sheet_data_with_data(sheet_data, data):
112
+    """
113
+    Merge `sheet_data` with `data`.
114
+
115
+    :param sheet_data: Dictionary containing the sheet-specific data.
116
+    :param data: Dictionary containing general data.
117
+    :return: A merged dictionary combining both `sheet_data` and `data`.
118
+    """
119
+    # Merge dictionaries using unpacking
120
+    merged_data = {**data, **sheet_data}
121
+
122
+    return merged_data
123
+
124
+def create_coi_file(lot_no, sheets, user, md):
125
+    pprint("---- create_coi_file ---")
126
+    pprint(md)
127
+    qa1 = User.objects.get(pk=md['qa1'])
128
+    qa2 = User.objects.get(pk=md['qa2'])
129
+
130
+    pprint(qa1)
131
+    pprint(qa2)
132
+    
133
+    sheet_data = {}
134
+    for sheet_name in sheets:
135
+        if sheet_name == 'hardness_out':
136
+            sheet_data[sheet_name] = generate_hardness_out_values(lot_no)
137
+    converted_data = convert_sheet_data(sheet_data)
138
+
139
+    print(f"sheet_data \n {sheet_data}") 
140
+    print(f"converted_data \n {converted_data}")
71
 
141
 
72
     data = {
142
     data = {
73
         "customer": "Tum Coder",
143
         "customer": "Tum Coder",
78
         "size": "Large",
148
         "size": "Large",
79
         "pcs": "10 pcs",
149
         "pcs": "10 pcs",
80
         "spec": "Spec-A",
150
         "spec": "Spec-A",
81
-        "hardness_out.d1_act": "10",
82
-        "hardness_out.d2_act": "0[24:28]",  # Hide rows 24 to 28 if the prefix is "0"
83
         "hardness_out.acc": True,  # Hide rows 24 to 28 if the prefix is "0"
151
         "hardness_out.acc": True,  # Hide rows 24 to 28 if the prefix is "0"
84
         "hardness_out.spe_acc": False,  # Hide rows 24 to 28 if the prefix is "0"
152
         "hardness_out.spe_acc": False,  # Hide rows 24 to 28 if the prefix is "0"
85
-        "hardness_out.qa1": "Hello world",
86
-        "hardness_out.qa2": "Unknow person",
87
-        "hardness_out.v11": 5,
88
-        "hardness_out.v12": 15,
89
-        "hardness_out.v13": 10,
90
-        "hardness_out.v21": 9,
91
-        "hardness_out.v22": 8,
92
-        "hardness_out.v23": 7,
153
+        "acc": True,  # Hide rows 24 to 28 if the prefix is "0"
154
+        "spe_acc": True,  # Hide rows 24 to 28 if the prefix is "0"
155
+        # "hardness_out.qa1": f"{qa1.first_name} {qa1.last_name}",
156
+        # "hardness_out.qa2": f"{qa2.first_name} {qa2.last_name}",
157
+        "qa1": f"{qa1.first_name} {qa1.last_name}",
158
+        "qa2": f"{qa2.first_name} {qa2.last_name}",
93
         "dimension_app.d1_act": "33",
159
         "dimension_app.d1_act": "33",
94
         "dimension_app.d2_act": "0[26:32]",  # Hide rows 24 to 28 if the prefix is "0"
160
         "dimension_app.d2_act": "0[26:32]",  # Hide rows 24 to 28 if the prefix is "0"
95
         "dimension_app.acc": True,  # Hide rows 24 to 28 if the prefix is "0"
161
         "dimension_app.acc": True,  # Hide rows 24 to 28 if the prefix is "0"
96
         "dimension_app.spe_acc": True,  # Hide rows 24 to 28 if the prefix is "0"
162
         "dimension_app.spe_acc": True,  # Hide rows 24 to 28 if the prefix is "0"
97
-        "sign1": user.profile.signed_picture,
98
-        "sign2": user.profile.signed_picture,
163
+        "sign1": qa1.profile.signed_picture,
164
+        "sign2": qa2.profile.signed_picture,
165
+        "pos1": qa1.profile.get_position_display(),
166
+        "pos2": qa2.profile.get_position_display()
99
     }
167
     }
168
+    merged_data = merge_sheet_data_with_data(converted_data, data)
169
+    pprint(f"---- merged_data ---")
170
+    pprint(merged_data)
171
+
100
     output_file = gen_xlsx(
172
     output_file = gen_xlsx(
101
         template_file="/app/report/coi_templates.xlsx",
173
         template_file="/app/report/coi_templates.xlsx",
102
         selected_sheets=sheets,  # Replace with your actual sheet names
174
         selected_sheets=sheets,  # Replace with your actual sheet names
103
         prefix_filename="/app/media/coi",
175
         prefix_filename="/app/media/coi",
104
-        data=data
176
+        data=merged_data
105
     )
177
     )
106
     report = Report.objects.create(
178
     report = Report.objects.create(
107
         name=lot_no,
179
         name=lot_no,
201
         try:
273
         try:
202
             # Parse JSON data from the request body
274
             # Parse JSON data from the request body
203
             data = json.loads(request.body)
275
             data = json.loads(request.body)
204
-            lot_no = data.get("lot_no")
276
+            lot_no = data.get("lot_no").strip()
205
             exports = data.get("exports")
277
             exports = data.get("exports")
278
+            qa1 = data.get('qa1')
279
+            qa2 = data.get('qa2')
280
+            print(f"data = {data}")
206
 
281
 
207
             if not lot_no:
282
             if not lot_no:
208
                 return HttpResponseBadRequest("Missing 'lot_no' in request data")
283
                 return HttpResponseBadRequest("Missing 'lot_no' in request data")
209
 
284
 
210
             # Call the `create_coi_file` function with the provided lot_no
285
             # Call the `create_coi_file` function with the provided lot_no
211
-            report = create_coi_file(lot_no, exports, request.user)
286
+            report = create_coi_file(lot_no, exports, request.user, {'qa1': qa1, 'qa2': qa2})
212
 
287
 
213
             # Return a success response with the report details
288
             # Return a success response with the report details
214
             return JsonResponse({
289
             return JsonResponse({

+ 2 - 1
app/sysadmin/models.py

19
     position = models.CharField(max_length=20, choices=POSITION_CHOICES, blank=True, null=True)  # New position field
19
     position = models.CharField(max_length=20, choices=POSITION_CHOICES, blank=True, null=True)  # New position field
20
 
20
 
21
     def __str__(self):
21
     def __str__(self):
22
-        return f"{self.user.username} / {self.user.first_name} {self.user.last_name} #{self.position}"
22
+        pos = self.get_position_display()
23
+        return f"{self.user.username} / {self.user.first_name} {self.user.last_name} #{pos}"