Browse Source

last update

tum 1 week ago
parent
commit
e67b3386c0

+ 2 - 2
app/coi/settings.py

@@ -184,11 +184,11 @@ AUTH_PASSWORD_VALIDATORS = [
184 184
 
185 185
 LANGUAGE_CODE = "en-us"
186 186
 
187
-TIME_ZONE = "Asia/Bangkok"
187
+#TIME_ZONE = "Asia/Bangkok"
188 188
 
189 189
 USE_I18N = True
190 190
 
191
-USE_TZ = True
191
+#USE_TZ = True
192 192
 
193 193
 
194 194
 # Static files (CSS, JavaScript, Images)

+ 2 - 1
app/core/utils.py

@@ -229,7 +229,8 @@ def queryFromMaster(lot_no):
229 229
 
230 230
 SHEET_NAMES = {
231 231
     'hardness_out': '1. Hardness Out',
232
-    'hardness_out_in': '2. Hardness Out/In', 
232
+    'hardness_out_in': '2.1 Hardness Out/In', 
233
+    'hardness_out_in_4': '2.2 Hardness Out/In 4 Points', 
233 234
     'hardness_both_size': '3. Hardness Both Size',
234 235
     'dimension': '4.1 Dimension',
235 236
     'dimension_weight_warp': '4.2 Dimension/Weight/Warp',

BIN
app/report/coi_templates-old.xlsx


BIN
app/report/coi_templates.xlsx


+ 62 - 7
app/report/gen_report.py

@@ -15,7 +15,7 @@ from pprint import pprint
15 15
 from PIL import Image as PILImage
16 16
 from openpyxl.drawing.xdr import XDRPoint2D, XDRPositiveSize2D
17 17
 from openpyxl.utils.units import pixels_to_EMU
18
-from openpyxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor
18
+from openpyxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor,  OneCellAnchor
19 19
 from django.conf import settings
20 20
 
21 21
 def set_image_with_offset_old(sheet, img, cell_coordinate, offset_x=0, offset_y=0):
@@ -95,10 +95,64 @@ def set_image_with_offset(sheet, img, cell_coordinate, offset_x=0, offset_y=0):
95 95
     # Add the image to the worksheet
96 96
     sheet.add_image(img)
97 97
 
98
-
98
+from openpyxl.drawing.xdr import XDRPositiveSize2D
99 99
 
100 100
 def center_image_in_cell(sheet, img, cell_coordinate):
101 101
     """
102
+    Center an image inside a specified cell using OneCellAnchor.
103
+    """
104
+
105
+    # Extract column and row (e.g. "C3")
106
+    col_letter = ''.join(filter(str.isalpha, cell_coordinate))
107
+    row_number = int(''.join(filter(str.isdigit, cell_coordinate)))
108
+    col_idx = column_index_from_string(col_letter) - 1  # Zero-based index
109
+
110
+    # Get cell size (Excel default values if not set)
111
+    col_width = sheet.column_dimensions[col_letter].width or 8.43
112
+    row_height = sheet.row_dimensions[row_number].height or 15
113
+
114
+    # Convert Excel column/row units → pixels
115
+    col_pixels = col_width * 7.5
116
+    row_pixels = row_height * 0.75
117
+
118
+    # Image size (already in pixels)
119
+    img_width, img_height = img.width, img.height
120
+
121
+    # Calculate centering offset inside the cell
122
+    offset_x_px = max((col_pixels - img_width) / 2, 0)
123
+    offset_y_px = max((row_pixels - img_height) / 2, 0)
124
+
125
+    offset_x_px += 40
126
+    offset_y_px -= 50
127
+
128
+    # Convert pixel offset to EMU
129
+    offset_x = pixels_to_EMU(offset_x_px)
130
+    offset_y = pixels_to_EMU(offset_y_px)
131
+
132
+    # Create the `_from` anchor marker (top-left corner)
133
+    _from = AnchorMarker(
134
+        col=col_idx,
135
+        row=row_number - 1,
136
+        colOff=offset_x,
137
+        rowOff=offset_y
138
+    )
139
+
140
+    # Create XDRPositiveSize2D for ext (width & height in EMU)
141
+    ext = XDRPositiveSize2D(
142
+        cx=pixels_to_EMU(img_width),
143
+        cy=pixels_to_EMU(img_height)
144
+    )
145
+
146
+    # Final anchor using OneCellAnchor
147
+    img.anchor = OneCellAnchor(
148
+        _from=_from,
149
+        ext=ext
150
+    )
151
+
152
+    sheet.add_image(img)
153
+
154
+def center_image_in_cell_old(sheet, img, cell_coordinate):
155
+    """
102 156
     Center an image inside a specified cell.
103 157
 
104 158
     :param sheet: The worksheet
@@ -122,7 +176,7 @@ def center_image_in_cell(sheet, img, cell_coordinate):
122 176
     img_width, img_height = img.width, img.height
123 177
 
124 178
     # Calculate offsets to center the image
125
-    offset_x = int((col_pixels - img_width) / 2 * pixels_to_EMU(1))  # Center horizontally
179
+    offset_x = int((col_pixels - img_width) / 2 * pixels_to_EMU(1)) + 100 # Center horizontally
126 180
     offset_y = int((row_pixels - img_height) / 2 * pixels_to_EMU(1))  # Center vertically
127 181
 
128 182
     # Define the anchor for the image
@@ -201,9 +255,10 @@ def gen_xlsx(template_file, selected_sheets, prefix_filename, data):
201 255
 
202 256
                                 # Desired height (e.g., 40), calculate the new width to maintain aspect ratio
203 257
                                 row_height = sheet.row_dimensions[cell.row].height
204
-                                desired_height = int(row_height)
258
+                                desired_height = int(row_height) 
205 259
 
206 260
                                 fixed_pixel_height = int(desired_height * 1.33)  # Convert point → pixel
261
+                                fixed_pixel_height = 100  # Convert point → pixel
207 262
 
208 263
                                 aspect_ratio = original_width / original_height
209 264
                                 new_width = int(fixed_pixel_height * aspect_ratio)
@@ -224,7 +279,7 @@ def gen_xlsx(template_file, selected_sheets, prefix_filename, data):
224 279
                                 pprint(f"1.2 = {new_width}, {desired_height}")
225 280
                                 # Insert the resized image into the Excel sheet
226 281
                                 img = Image(resized_path)
227
-                                img.width, img.height = new_width, desired_height  # Set the dimensions
282
+                                img.width, img.height = new_width, fixed_pixel_height  # Set the dimensions
228 283
                                 # sheet.add_image(img, cell.coordinate)
229 284
                                 print(f"1.3 = {row_height}")
230 285
                                 center_image_in_cell(sheet, img, cell.coordinate, )
@@ -240,7 +295,7 @@ def gen_xlsx(template_file, selected_sheets, prefix_filename, data):
240 295
                             print(f"{cell.coordinate}")
241 296
                             # sheet.add_image(img, cell.coordinate)
242 297
                             # set_image_with_offset(sheet, img, cell.coordinate, offset_x=100)
243
-                            center_image_in_cell(sheet,img, cell.coordinate, )
298
+                            center_image_in_cell_old(sheet,img, cell.coordinate, )
244 299
                             cell.value = None  # Remove the placeholder text
245 300
                         elif value is False:
246 301
                             img = Image(unchecked_image_path)
@@ -250,7 +305,7 @@ def gen_xlsx(template_file, selected_sheets, prefix_filename, data):
250 305
                             img.height = pixels_to_points(10)
251 306
                             # sheet.add_image(img, cell.coordinate)
252 307
                             # set_image_with_offset(sheet, img, cell.coordinate, offset_x=100)
253
-                            center_image_in_cell(sheet, img, cell.coordinate, )
308
+                            center_image_in_cell_old(sheet, img, cell.coordinate, )
254 309
                             cell.value = None  # Remove the placeholder text
255 310
                         else:
256 311
                             # Insert the text value directly

+ 82 - 29
app/report/views.py

@@ -165,29 +165,31 @@ def generate_hardness_out_in_values(lot_no, code):
165 165
     for record in records:
166 166
         if record.r_type.upper() in ["OUT", "TOP", "FA1", "UPP", "UPPE", "RIM"]:
167 167
             out_data.append(record)
168
-        elif record.r_type.upper() in ["IN", "UNDER", "UND", "FA2", "LOW", "LOWE", "BASE", "SOKO", "IN*"]:
168
+        elif record.r_type.upper() in ["IN", "UNDER", "UND", "FA2", "LOW", "LOWE", "BASE", "SOKO", "IN*", "INNER"]:
169 169
             in_data.append(record)
170 170
 
171 171
     # Prepare placeholders
172 172
     # placeholders = {}
173
-    placeholders = clear_values(4,5)
173
+    placeholders = clear_values(4,6)
174 174
     inspect_date = None
175
-    for idx, record in enumerate(out_data, start=1):
175
+    for idx, record in enumerate(out_data, start=0):
176 176
         if idx == 1:
177 177
             inspect_date = record.created_at
178 178
 
179
-        placeholders[f'v{idx}_1'] = record.p1
180
-        placeholders[f'v{idx}_2'] = record.p2
181
-        placeholders[f'v{idx}_3'] = record.p3
182
-        placeholders[f'v{idx}_4'] = record.avg
183
-        placeholders[f'v{idx}_5'] = record.rgrade
179
+        placeholders[f'v{2*idx+1}_1'] = record.p1
180
+        placeholders[f'v{2*idx+1}_2'] = record.p2
181
+        placeholders[f'v{2*idx+1}_3'] = record.p3
182
+        placeholders[f'v{2*idx+1}_6'] = record.p4  # Checkpoint 3 value
183
+        placeholders[f'v{2*idx+1}_4'] = record.avg
184
+        placeholders[f'v{2*idx+1}_5'] = record.rgrade
184 185
 
185 186
     for idx, record in enumerate(in_data, start=1):
186
-        placeholders[f'v{len(out_data) + idx}_1'] = record.p1
187
-        placeholders[f'v{len(out_data) + idx}_2'] = record.p2
188
-        placeholders[f'v{len(out_data) + idx}_3'] = record.p3
189
-        placeholders[f'v{len(out_data) + idx}_4'] = record.avg
190
-        placeholders[f'v{len(out_data) + idx}_5'] = record.rgrade
187
+        placeholders[f'v{idx*2}_1'] = record.p1
188
+        placeholders[f'v{idx*2}_2'] = record.p2
189
+        placeholders[f'v{idx*2}_3'] = record.p3
190
+        placeholders[f'v{idx*2}_6'] = record.p4
191
+        placeholders[f'v{idx*2}_4'] = record.avg
192
+        placeholders[f'v{idx*2}_5'] = record.rgrade
191 193
 
192 194
     # if "v3_1" in placeholders:
193 195
         # placeholders["v3_1"] = f"{placeholders['v3_1']}[25:28]"
@@ -691,11 +693,17 @@ def generate_dim_bal_app_hard_values(lot_no, first_result, code):
691 693
         except (TypeError, ValueError):
692 694
             out_limit = "Out 外"
693 695
 
694
-        try:
695
-            in_limit = f"In 内 ({float(first_result.MI22):.2f} - {float(first_result.MI23):.2f})"
696
-        except (TypeError, ValueError):
697
-            in_limit = "In 内"
696
+        mi22 = getattr(first_result, "MI22", None)
697
+        mi23 = getattr(first_result, "MI23", None)
698 698
 
699
+        # If MI22 is missing, None, 0, or ""
700
+        if mi22 in (None, 0, "", "0"):
701
+            in_limit = "In 内: -"
702
+        else:
703
+            try:
704
+                in_limit = f"In 内 ({float(mi22):.2f} - {float(mi23 or 0):.2f})"
705
+            except (TypeError, ValueError):
706
+                in_limit = "In 内: -"
699 707
         mid_limit = f"Middle   中  -"
700 708
     else:
701 709
         out_limit = f"Out 外"
@@ -719,19 +727,19 @@ def generate_dim_bal_app_hard_values(lot_no, first_result, code):
719 727
     pprint(manual_size_records) 
720 728
     if first_result:
721 729
         try:
722
-            w = first_result.PRO6
723
-            placeholders['v4_1'] = placeholders['v12_1'] = w
730
+            w = first_result.MI24
731
+            placeholders['v4_1'] = placeholders['v12_1'] = f"{w}"
724 732
         except:
725 733
             print("No PRO6")
726 734
 
727 735
     dimens = AllProductDimensionForInsProcess.objects.filter(ProductCode=code)
728 736
     for m in dimens:  # Changed from manual_size_records to dimens
729 737
         if m.Size_Name == "D":
730
-            placeholders['v1_1'] = placeholders['v9_1'] = f'D{m.Std:.2f} +{m.TolUp:.2f} {m.TolUn:.2f}'
738
+            placeholders['v1_1'] = placeholders['v9_1'] = f'D{m.Std:.2f} +{m.TolUp:.2f}/{m.TolUn:.2f}'
731 739
         if m.Size_Name == "T":
732
-            placeholders['v2_1'] = placeholders['v10_1'] = f'T{m.Std:.2f} +{m.TolUp:.2f} {m.TolUn:.2f}'
740
+            placeholders['v2_1'] = placeholders['v10_1'] = f'T{m.Std:.2f} +{m.TolUp:.2f}/{m.TolUn:.2f}'
733 741
         if m.Size_Name == "H":
734
-            placeholders['v3_1'] = placeholders['v11_1'] = f'H{m.Std:.2f} +{m.TolUp:.2f} {m.TolUn:.2f}'
742
+            placeholders['v3_1'] = placeholders['v11_1'] = f'H{m.Std:.2f} +{m.TolUp:.2f}/{m.TolUn:.2f}'
735 743
 
736 744
     inspect_date = None
737 745
     # Ensure that we map each manualSize entry to a corresponding DataMs entry
@@ -773,10 +781,10 @@ def generate_dim_bal_app_hard_values(lot_no, first_result, code):
773 781
 
774 782
     for r in data_wb:
775 783
         if r.row_no == 1:
776
-            placeholders["v4_2"] = r.weight
784
+            placeholders["v4_2"] = f"{r.weight:.1f}"
777 785
             placeholders["v4_3"] = r.judgement
778 786
         if r.row_no == 2:
779
-            placeholders["v12_2"] = r.weight
787
+            placeholders["v12_2"] = f"{r.weight:.1f}"
780 788
             placeholders["v12_3"] = r.judgement
781 789
 
782 790
     for r in data_ho:
@@ -827,10 +835,17 @@ def generate_dim_bal_app_rot_hard_values(lot_no, first_result, code):
827 835
         except (TypeError, ValueError):
828 836
             out_limit = "Out 外"
829 837
 
830
-        try:
831
-            in_limit = f"In 内 ({float(first_result.MI22):.2f} - {float(first_result.MI23):.2f})"
832
-        except (TypeError, ValueError):
838
+        mi22 = getattr(first_result, "MI22", None)
839
+        mi23 = getattr(first_result, "MI23", None)
840
+
841
+        # If MI22 is missing, None, 0, or ""
842
+        if mi22 in (None, 0, "", "0"):
833 843
             in_limit = "In 内"
844
+        else:
845
+            try:
846
+                in_limit = f"In 内 ({float(mi22):.2f} - {float(mi23 or 0):.2f})"
847
+            except (TypeError, ValueError):
848
+                in_limit = "In 内"
834 849
 
835 850
         mid_limit = f"Middle   中  -"
836 851
     else:
@@ -911,10 +926,10 @@ def generate_dim_bal_app_rot_hard_values(lot_no, first_result, code):
911 926
 
912 927
     for r in data_wb:
913 928
         if r.row_no == 1:
914
-            placeholders["v4_2"] = r.weight
929
+            placeholders["v4_2"] = f"{r.weight:.1f}"
915 930
             placeholders["v4_3"] = r.judgement
916 931
         if r.row_no == 2:
917
-            placeholders["v13_2"] = r.weight
932
+            placeholders["v13_2"] = f"{r.weight:.1f}"
918 933
             placeholders["v13_3"] = r.judgement
919 934
 
920 935
     for r in data_ho:
@@ -1061,6 +1076,8 @@ def create_coi_file(lot_no, sheets, user, md):
1061 1076
             sheet_data[sheet_name] = generate_hardness_out_values(lot_no, code)
1062 1077
         elif sheet_name == 'hardness_out_in':
1063 1078
             sheet_data[sheet_name] = generate_hardness_out_in_values(lot_no, code)
1079
+        elif sheet_name == 'hardness_out_in_4':
1080
+            sheet_data[sheet_name] = generate_hardness_out_in_values(lot_no, code)
1064 1081
         elif sheet_name == 'hardness_both_size':
1065 1082
             sheet_data[sheet_name] = generate_hardness_both_size_values(lot_no, first_result, code)
1066 1083
         elif sheet_name == 'dimension':
@@ -1139,7 +1156,42 @@ def create_coi_file(lot_no, sheets, user, md):
1139 1156
     tn = get_tool_no(mgt_code)
1140 1157
     if tn is None:
1141 1158
         tn = first_result.PRO_TOOL if first_result and first_result.PRO_TOOL else "-"
1159
+# Helper function
1160
+    def safe_float(value):
1161
+        try:
1162
+            return float(value)
1163
+        except (TypeError, ValueError):
1164
+            return 0
1165
+
1166
+    # MP45 or fallback MP34
1167
+    mp45_value = getattr(first_result, "MP45", None)
1168
+    mp45_or_34 = mp45_value if mp45_value not in (None, "") else getattr(first_result, "MP34", "")
1169
+
1170
+    # MP49 or fallback MP39
1171
+    mp49_value = getattr(first_result, "MP49", None)
1172
+    mp49_or_39 = mp49_value if mp49_value not in (None, "") else getattr(first_result, "MP39", None)
1173
+
1174
+    # Build first part (always present)
1175
+    part1 = (
1176
+        f"Hardness: {getattr(first_result, 'ob_Condition', '')}, "
1177
+        f"{mp45_or_34} "
1178
+        f"{safe_float(getattr(first_result, 'MI18', None)):.2f} - "
1179
+        f"{safe_float(getattr(first_result, 'MI19', None)):.2f} "
1180
+        f"({getattr(first_result, 'MI16', '')} {getattr(first_result, 'MI17', '')})"
1181
+    )
1182
+
1183
+    # Build second part only if mp49_or_39 exists
1184
+    if mp49_or_39 not in (None, ""):
1185
+        part2 = (
1186
+            f" {mp49_or_39}: "
1187
+            f"{safe_float(getattr(first_result, 'MI22', None)):.2f} - "
1188
+            f"{safe_float(getattr(first_result, 'MI23', None)):.2f} "
1189
+            f"({getattr(first_result, 'MI20', '')} {getattr(first_result, 'MI21', '')})"
1190
+        )
1191
+    else:
1192
+        part2 = ""  # exclude second part entirely
1142 1193
 
1194
+    std_value = part1 + part2
1143 1195
     data = {
1144 1196
         # "code": first_result.PRO1 if first_result else "-",
1145 1197
         "code": code,
@@ -1149,6 +1201,7 @@ def create_coi_file(lot_no, sheets, user, md):
1149 1201
         "size": size_str,
1150 1202
         "lot_size": pcs,
1151 1203
         "spec": spec,
1204
+        "std": std_value,
1152 1205
         # "hardness_out.acc": True,  # Hide rows 24 to 28 if the prefix is "0"
1153 1206
         # "hardness_out.spe_acc": False,  # Hide rows 24 to 28 if the prefix is "0"
1154 1207
         "acc": accept,  # Hide rows 24 to 28 if the prefix is "0"