Ei kuvausta

views.py 39KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. from django.shortcuts import render, redirect, get_object_or_404
  2. from django.core.paginator import Paginator
  3. from django.contrib import messages
  4. from core.models import Report, AllProductDimensionForInsProcess
  5. from core.forms import ReportForm
  6. from core.utils import ConfigurableCRUDView, queryFromMaster
  7. from .filters import ReportFilter
  8. from .forms import ExportOptionsForm
  9. from pprint import pprint
  10. from legacy.models import Data, DataMs, DataRl, DataWb, LotSummary, LotSummaryRl, LotSummaryWb, PressCal, RotateData, TbFgPressinfoLotlist,\
  11. Manualsize
  12. from .gen_report import gen_xlsx
  13. from django.core.files.base import File
  14. from pathlib import Path
  15. from django.views.decorators.csrf import csrf_exempt
  16. from django.http import JsonResponse, HttpResponseBadRequest
  17. import json
  18. from django.contrib.auth.decorators import login_required
  19. from django.contrib.auth.models import User
  20. from legacy.models import Data
  21. from django.conf import settings
  22. from itertools import chain
  23. def index(request):
  24. reports = Report.objects.all()
  25. report_filter = ReportFilter(request.GET, queryset=reports)
  26. # Paginate the filtered queryset
  27. paginator = Paginator(report_filter.qs, 10) # Show 10 reports per page
  28. page_number = request.GET.get('page')
  29. page_obj = paginator.get_page(page_number)
  30. context = {
  31. 'filter': report_filter,
  32. 'page_obj': page_obj,
  33. }
  34. return render(request, 'report/index.html', context)
  35. def report_create_view(request):
  36. if request.method == "POST":
  37. form = ReportForm(request.POST)
  38. if form.is_valid():
  39. form.save()
  40. messages.success(request, "Report created successfully!")
  41. return redirect("report:report_index") # Adjust with your report list view name
  42. else:
  43. form = ReportForm()
  44. return render(request, "report/create.html", {"form": form})
  45. class ReportCRUDView(ConfigurableCRUDView):
  46. model = Report
  47. list_template_name = 'legacy/datacrud_list.html'
  48. detail_template_name = 'legacy/datacrud_detail.html'
  49. form_template_name = 'report/report_form.html'
  50. confirm_delete_template_name = 'legacy/datacrud_confirm_delete.html'
  51. filterset_class = ReportFilter
  52. page_title = "Reports"
  53. # URL name mappings
  54. list_url_name = 'report:report-list'
  55. create_url_name = 'report:report-create'
  56. update_url_name = 'report:report-update'
  57. delete_url_name = 'report:report-delete'
  58. config_fields = ["name", "file", "created_by", "created_at"]
  59. config_field_orders = ["id", "name", "created_by"]
  60. # config_readonly_fields = ["lot_no"]
  61. # config_edit_fields = ["lot_no", "code"]
  62. ordering = ["-created_at", "-id",]
  63. def convert_sheet_data(sheet_data):
  64. """
  65. Convert sheet_data to the required form with prefixed keys.
  66. :param sheet_data: Dictionary with sheet names as keys and their data as values.
  67. :return: Dictionary in the required key-value format.
  68. """
  69. converted_data = {}
  70. for sheet_name, data in sheet_data.items():
  71. for key, value in data.items():
  72. # Prefix each key with the sheet name
  73. converted_key = f"{sheet_name}.{key}"
  74. converted_data[converted_key] = value
  75. return converted_data
  76. def hide_con(placeholders, mark_value, hide_rows):
  77. """
  78. Updates the 'placeholders' dictionary with a mark value and hide rows range.
  79. :param placeholders: The dictionary to update.
  80. :param mark_value: The key to check or update in the placeholders.
  81. :param hide_rows: The row range to append in the format '[start:end]'.
  82. """
  83. if mark_value in placeholders:
  84. placeholders[mark_value] = f"{placeholders[mark_value]}[{hide_rows}]"
  85. else:
  86. placeholders[mark_value] = f"0[{hide_rows}]"
  87. def clear_values(n, m):
  88. placeholders = {}
  89. for i in range(1, n + 1):
  90. for j in range(1, m + 1):
  91. placeholders[f'v{i}_{j}'] = " "
  92. return placeholders
  93. def generate_hardness_out_values(lot_no, code):
  94. """
  95. Generate a dictionary of placeholder values for a given lot_no.
  96. :param lot_no: The lot number to query data for.
  97. :return: A dictionary with placeholders (e.g., v1_1, v1_2, ...) as keys and their respective values.
  98. """
  99. # Query the Data model for records matching the given lot_no
  100. # records = Data.objects.filter(lot_no=lot_no).order_by('row_no')
  101. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no'))
  102. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no'))
  103. records = list(chain(data_h1, data_h2))
  104. print(f"records {lot_no} = {records.values()}")
  105. # Initialize an empty dictionary to store placeholder values
  106. placeholders = clear_values(2,5)
  107. # Iterate over the records to populate placeholder values
  108. for record_idx, record in enumerate(records, start=1):
  109. placeholders[f'v{record_idx}_1'] = record.p1 # Checkpoint 1 value
  110. placeholders[f'v{record_idx}_2'] = record.p2 # Checkpoint 2 value
  111. placeholders[f'v{record_idx}_3'] = record.p3 # Checkpoint 3 value
  112. placeholders[f'v{record_idx}_4'] = record.avg # Average value
  113. placeholders[f'v{record_idx}_5'] = record.rgrade # Judgment value
  114. return placeholders
  115. def generate_hardness_out_in_values(lot_no, code):
  116. # Fetch records from the Data model
  117. # records = Data.objects.filter(lot_no=lot_no).order_by('row_no')
  118. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no'))
  119. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no'))
  120. records = list(chain(data_h1, data_h2))
  121. out_data = []
  122. in_data = []
  123. # Separate OUT and IN data
  124. for record in records:
  125. if record.r_type.upper() in ["OUT", "TOP", "FA1", "UPP", "UPPE", "RIM"]:
  126. out_data.append(record)
  127. elif record.r_type.upper() in ["IN", "UNDER", "UND", "FA2", "LOW", "LOWE", "BASE", "SOKO", "IN*"]:
  128. in_data.append(record)
  129. # Prepare placeholders
  130. # placeholders = {}
  131. placeholders = clear_values(4,5)
  132. for idx, record in enumerate(out_data, start=1):
  133. placeholders[f'v{idx}_1'] = record.p1
  134. placeholders[f'v{idx}_2'] = record.p2
  135. placeholders[f'v{idx}_3'] = record.p3
  136. placeholders[f'v{idx}_4'] = record.avg
  137. placeholders[f'v{idx}_5'] = record.rgrade
  138. for idx, record in enumerate(in_data, start=1):
  139. placeholders[f'v{len(out_data) + idx}_1'] = record.p1
  140. placeholders[f'v{len(out_data) + idx}_2'] = record.p2
  141. placeholders[f'v{len(out_data) + idx}_3'] = record.p3
  142. placeholders[f'v{len(out_data) + idx}_4'] = record.avg
  143. placeholders[f'v{len(out_data) + idx}_5'] = record.rgrade
  144. # if "v3_1" in placeholders:
  145. # placeholders["v3_1"] = f"{placeholders['v3_1']}[25:28]"
  146. # else:
  147. # placeholders[f"v3_1"] = "0[25:28]"
  148. hide_con(placeholders, "v3_1", "25:28")
  149. return placeholders
  150. def generate_hardness_both_size_values(lot_no, ms,code):
  151. # Fetch records from the Data model
  152. # records = Data.objects.filter(lot_no=lot_no).order_by('row_no')
  153. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no', 'sub_order'))
  154. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no', 'sub_order'))
  155. records = list(chain(data_h1, data_h2))
  156. out_data = []
  157. in_data = []
  158. placeholders = clear_values(20,5)
  159. # Separate OUT and IN data
  160. for idx, record in enumerate(records, start=0):
  161. if record.sub_order == 1:
  162. for i,v in enumerate(["p1", "p2", "p3", "avg", "rgrade"],start=1):
  163. placeholders[f"v{idx*2+1}_{i}"] = getattr(record,v)
  164. if record.sub_order == 2:
  165. for i,v in enumerate(["p1", "p2", "p3", "avg", "rgrade"],start=1):
  166. placeholders[f"v{idx*2+2}_{i}"] = getattr(record,v)
  167. # Prepare placeholders
  168. # placeholders = {}
  169. return placeholders
  170. # # Example usage:
  171. # placeholders_dict = clear_values(6, 3)
  172. # print(placeholders_dict)
  173. def generate_dimension_values(lot_no, code):
  174. """
  175. Fetch dimension records from manualSize and DataMs models
  176. and generate placeholder values for Standard, Actual, and Judgement.
  177. Supports two row_no entries per lot.
  178. """
  179. # Fetch standard values from manualSize (limit to 2 rows)
  180. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  181. dimens = AllProductDimensionForInsProcess.objects.filter(ProductCode=code)
  182. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  183. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  184. # Prepare placeholders
  185. # placeholders = {}
  186. placeholders = clear_values(7,4)
  187. # for i in range(1,7):
  188. # for j in range(1,4):
  189. # placeholders[f'v{i}_{j}'] = 0
  190. pprint(placeholders)
  191. pprint(manual_size_records)
  192. for m in dimens:
  193. if m.Size_Name == "D":
  194. placeholders['v1_1'] = placeholders['v4_1'] = f'D{m.Std} +{m.TolUp} {m.TolUn}'
  195. if m.Size_Name == "T":
  196. placeholders['v2_1'] = placeholders['v5_1'] = f'T{m.Std} +{m.TolUp} {m.TolUn}'
  197. if m.Size_Name == "H":
  198. placeholders['v3_1'] = placeholders['v6_1'] = f'H{m.Std} +{m.TolUp} {m.TolUn}'
  199. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  200. for r in data_ms_records:
  201. if r.row_no == 1:
  202. placeholders[f'v1_2'] = r.dsize
  203. placeholders[f'v1_3'] = r.dsizeok
  204. placeholders[f'v2_2'] = r.tsize
  205. placeholders[f'v2_3'] = r.tsizeok
  206. placeholders[f'v3_2'] = r.hsize
  207. placeholders[f'v3_3'] = r.hsizeok
  208. if r.row_no == 2:
  209. placeholders[f'v4_2'] = r.dsize
  210. placeholders[f'v4_3'] = r.dsizeok
  211. placeholders[f'v5_2'] = r.tsize
  212. placeholders[f'v5_3'] = r.tsizeok
  213. placeholders[f'v6_2'] = r.hsize
  214. placeholders[f'v6_3'] = r.hsizeok
  215. hide_con(placeholders, "v4_1", "24:28")
  216. return placeholders
  217. def is_ok(instance):
  218. fields_and_values = {}
  219. for field in instance._meta.get_fields():
  220. field_name = field.name
  221. if field_name.endswith('ok'):
  222. v = getattr(instance, field_name)
  223. if v is not None and v != "OK":
  224. return False
  225. return True
  226. def generate_dimension_app_values(lot_no, code):
  227. """
  228. Fetch dimension records from manualSize and DataMs models
  229. and generate placeholder values for Standard, Actual, and Judgement.
  230. Supports two row_no entries per lot.
  231. """
  232. # Fetch standard values from manualSize (limit to 2 rows)
  233. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  234. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  235. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  236. # Prepare placeholders
  237. # placeholders = {}
  238. placeholders = clear_values(8,3)
  239. # for i in range(1,7):
  240. # for j in range(1,4):
  241. # placeholders[f'v{i}_{j}'] = 0
  242. pprint(placeholders)
  243. pprint(manual_size_records)
  244. for m in manual_size_records:
  245. if m.size_name == "D":
  246. placeholders['v1_1'] = placeholders['v5_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  247. if m.size_name == "T":
  248. placeholders['v2_1'] = placeholders['v6_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  249. if m.size_name == "H":
  250. placeholders['v3_1'] = placeholders['v7_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  251. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  252. for r in data_ms_records:
  253. if r.row_no == 1:
  254. placeholders[f'v1_2'] = r.dsize
  255. placeholders[f'v1_3'] = r.dsizeok
  256. placeholders[f'v2_2'] = r.tsize
  257. placeholders[f'v2_3'] = r.tsizeok
  258. placeholders[f'v3_2'] = r.hsize
  259. placeholders[f'v3_3'] = r.hsizeok
  260. # if is_ok(r):
  261. # placeholders[f'v4_1'] = 'OK'
  262. # placeholders[f'v4_2'] = 'OK'
  263. # else:
  264. # placeholders[f'v4_1'] = 'NG'
  265. # placeholders[f'v4_2'] = 'OK'
  266. if r.row_no == 2:
  267. placeholders[f'v5_2'] = r.dsize
  268. placeholders[f'v5_3'] = r.dsizeok
  269. placeholders[f'v6_2'] = r.tsize
  270. placeholders[f'v6_3'] = r.tsizeok
  271. placeholders[f'v7_2'] = r.hsize
  272. placeholders[f'v7_3'] = r.hsizeok
  273. # if is_ok(r):
  274. # placeholders[f'v8_1'] = 'OK'
  275. # placeholders[f'v8_2'] = 'OK'
  276. # else:
  277. # placeholders[f'v8_1'] = 'NG'
  278. # placeholders[f'v8_2'] = 'NG'
  279. hide_con(placeholders, "v5_1", "26:32")
  280. return placeholders
  281. def generate_dimension_bal_weight_values(lot_no, ms, code):
  282. """
  283. Fetch dimension records from manualSize and DataMs models
  284. and generate placeholder values for Standard, Actual, and Judgement.
  285. Supports two row_no entries per lot.
  286. """
  287. # Fetch standard values from manualSize (limit to 2 rows)
  288. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  289. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  290. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  291. data_wb = DataWb.objects.filter(lot_no=lot_no).order_by('row_no')
  292. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no'))
  293. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no'))
  294. data_ho = list(chain(data_h1, data_h2))
  295. # Prepare placeholders
  296. # placeholders = {}
  297. placeholders = clear_values(10,3)
  298. # for i in range(1,7):
  299. # for j in range(1,4):
  300. # placeholders[f'v{i}_{j}'] = 0
  301. pprint(placeholders)
  302. pprint(manual_size_records)
  303. if ms:
  304. w = ms.PRO6
  305. placeholders['v4_1'] = placeholders['v9_1'] = w
  306. for m in manual_size_records:
  307. if m.size_name == "D":
  308. placeholders['v1_1'] = placeholders['v6_1'] = f'D{m.std} +{m.tolup} {m.tolun}'
  309. if m.size_name == "T":
  310. placeholders['v2_1'] = placeholders['v7_1'] = f'T{m.std} +{m.tolup} {m.tolun}'
  311. if m.size_name == "H":
  312. placeholders['v3_1'] = placeholders['v8_1'] = f'H{m.std} +{m.tolup} {m.tolun}'
  313. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  314. for r in data_ms_records:
  315. if r.row_no == 1:
  316. placeholders[f'v1_2'] = r.dsize
  317. placeholders[f'v1_3'] = r.dsizeok
  318. placeholders[f'v2_2'] = r.tsize
  319. placeholders[f'v2_3'] = r.tsizeok
  320. placeholders[f'v3_2'] = r.hsize
  321. placeholders[f'v3_3'] = r.hsizeok
  322. # if is_ok(r):
  323. # placeholders[f'v4_1'] = 'OK'
  324. # placeholders[f'v4_2'] = 'OK'
  325. # else:
  326. # placeholders[f'v4_1'] = 'NG'
  327. # placeholders[f'v4_2'] = 'OK'
  328. if r.row_no == 2:
  329. placeholders[f'v6_2'] = r.dsize
  330. placeholders[f'v6_3'] = r.dsizeok
  331. placeholders[f'v7_2'] = r.tsize
  332. placeholders[f'v7_3'] = r.tsizeok
  333. placeholders[f'v8_2'] = r.hsize
  334. placeholders[f'v8_3'] = r.hsizeok
  335. # if is_ok(r):
  336. # placeholders[f'v8_1'] = 'OK'
  337. # placeholders[f'v8_2'] = 'OK'
  338. # else:
  339. # placeholders[f'v8_1'] = 'NG'
  340. # placeholders[f'v8_2'] = 'NG'
  341. for r in data_wb:
  342. if r.row_no == 1:
  343. placeholders["v4_2"] = r.result
  344. placeholders["v4_3"] = r.judgement
  345. placeholders["v5_2"] = r.weight
  346. placeholders["v5_3"] = r.judgement
  347. if r.row_no == 2:
  348. placeholders["v9_2"] = r.result
  349. placeholders["v9_3"] = r.judgement
  350. placeholders["v10_2"] = r.weight
  351. placeholders["v10_3"] = r.judgement
  352. # hide_con(placeholders, "v5_1", "26:32")
  353. return placeholders
  354. def generate_dim_bal_app_hard_values(lot_no, first_result, code):
  355. """
  356. Fetch dimension records from manualSize and DataMs models
  357. and generate placeholder values for Standard, Actual, and Judgement.
  358. Supports two row_no entries per lot.
  359. """
  360. # Fetch standard values from manualSize (limit to 2 rows)
  361. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  362. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  363. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  364. data_wb = DataWb.objects.filter(lot_no=lot_no).order_by('row_no')
  365. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no'))
  366. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no'))
  367. data_ho = list(chain(data_h1, data_h2))
  368. if first_result:
  369. out_limit = f"Out 外 ({first_result.MI18} - {first_result.MI19})"
  370. in_limit = f"In 内 ({first_result.MI22} - {first_result.MI23})"
  371. mid_limit = f"Middle 中 -"
  372. else:
  373. out_limit = f"Out 外"
  374. in_limit = f"In 内"
  375. mid_limit = f"Middle 中"
  376. # Prepare placeholders
  377. # placeholders = {}
  378. placeholders = clear_values(16,5)
  379. # for i in range(1,7):
  380. # for j in range(1,4):
  381. # placeholders[f'v{i}_{j}'] = 0
  382. placeholders['v6_0'] = placeholders['v14_0'] = out_limit
  383. placeholders['v7_0'] = placeholders['v15_0'] = mid_limit
  384. placeholders['v18_0'] = placeholders['v16_0'] = in_limit
  385. pprint(placeholders)
  386. pprint(manual_size_records)
  387. if first_result:
  388. w = first_result.PRO6
  389. placeholders['v4_1'] = placeholders['v12_1'] = w
  390. for m in manual_size_records:
  391. if m.size_name == "D":
  392. placeholders['v1_1'] = placeholders['v9_1'] = f'D{m.std} +{m.tolup} {m.tolun}'
  393. if m.size_name == "T":
  394. placeholders['v2_1'] = placeholders['v10_1'] = f'T{m.std} +{m.tolup} {m.tolun}'
  395. if m.size_name == "H":
  396. placeholders['v3_1'] = placeholders['v11_1'] = f'H{m.std} +{m.tolup} {m.tolun}'
  397. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  398. for r in data_ms_records:
  399. if r.row_no == 1:
  400. placeholders[f'v1_2'] = r.dsize
  401. placeholders[f'v1_3'] = r.dsizeok
  402. placeholders[f'v2_2'] = r.tsize
  403. placeholders[f'v2_3'] = r.tsizeok
  404. placeholders[f'v3_2'] = r.hsize
  405. placeholders[f'v3_3'] = r.hsizeok
  406. # if is_ok(r):
  407. # placeholders[f'v4_1'] = 'OK'
  408. # placeholders[f'v4_2'] = 'OK'
  409. # else:
  410. # placeholders[f'v4_1'] = 'NG'
  411. # placeholders[f'v4_2'] = 'OK'
  412. if r.row_no == 2:
  413. placeholders[f'v9_2'] = r.dsize
  414. placeholders[f'v9_3'] = r.dsizeok
  415. placeholders[f'v10_2'] = r.tsize
  416. placeholders[f'v10_3'] = r.tsizeok
  417. placeholders[f'v11_2'] = r.hsize
  418. placeholders[f'v11_3'] = r.hsizeok
  419. # if is_ok(r):
  420. # placeholders[f'v8_1'] = 'OK'
  421. # placeholders[f'v8_2'] = 'OK'
  422. # else:
  423. # placeholders[f'v8_1'] = 'NG'
  424. # placeholders[f'v8_2'] = 'NG'
  425. for r in data_wb:
  426. if r.row_no == 1:
  427. placeholders["v4_2"] = r.weight
  428. placeholders["v4_3"] = r.judgement
  429. if r.row_no == 2:
  430. placeholders["v12_2"] = r.weight
  431. placeholders["v12_3"] = r.judgement
  432. for r in data_ho:
  433. if r.row_no == 1:
  434. rmap = {'OUT': 6, 'MID': 7, 'IN': 8}
  435. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  436. idx = rmap.get(r.r_type, None)
  437. if idx:
  438. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  439. if r.row_no == 2:
  440. rmap = {'OUT': 14, 'MID': 15, 'IN': 16}
  441. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  442. idx = rmap.get(r.r_type, None)
  443. if idx:
  444. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  445. # hide_con(placeholders, "v5_1", "26:32")
  446. return placeholders
  447. def generate_dim_bal_app_rot_hard_values(lot_no, first_result, code):
  448. """
  449. Fetch dimension records from manualSize and DataMs models
  450. and generate placeholder values for Standard, Actual, and Judgement.
  451. Supports two row_no entries per lot.
  452. """
  453. # Fetch standard values from manualSize (limit to 2 rows)
  454. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  455. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  456. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  457. data_wb = DataWb.objects.filter(lot_no=lot_no).order_by('row_no')
  458. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no'))
  459. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no'))
  460. data_ho = list(chain(data_h1, data_h2))
  461. rotates = RotateData.objects.filter(lot_no=lot_no).order_by('row_no')
  462. if first_result:
  463. out_limit = f"Out 外 ({first_result.MI18} - {first_result.MI19})"
  464. in_limit = f"In 内 ({first_result.MI22} - {first_result.MI23})"
  465. mid_limit = f"Middle 中 -"
  466. else:
  467. out_limit = f"Out 外"
  468. in_limit = f"In 内"
  469. mid_limit = f"Middle 中"
  470. # Prepare placeholders
  471. # placeholders = {}
  472. placeholders = clear_values(18,5)
  473. # for i in range(1,7):
  474. # for j in range(1,4):
  475. # placeholders[f'v{i}_{j}'] = 0
  476. placeholders['v6_0'] = placeholders['v14_0'] = out_limit
  477. placeholders['v7_0'] = placeholders['v15_0'] = mid_limit
  478. placeholders['v18_0'] = placeholders['v16_0'] = in_limit
  479. pprint(placeholders)
  480. pprint(manual_size_records)
  481. if first_result:
  482. w = first_result.PRO6
  483. placeholders['v4_1'] = placeholders['v13_1'] = w
  484. for m in manual_size_records:
  485. if m.size_name == "D":
  486. placeholders['v1_1'] = placeholders['v10_1'] = f'D{m.std} +{m.tolup} {m.tolun}'
  487. if m.size_name == "T":
  488. placeholders['v2_1'] = placeholders['v11_1'] = f'T{m.std} +{m.tolup} {m.tolun}'
  489. if m.size_name == "H":
  490. placeholders['v3_1'] = placeholders['v12_1'] = f'H{m.std} +{m.tolup} {m.tolun}'
  491. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  492. for r in data_ms_records:
  493. if r.row_no == 1:
  494. placeholders[f'v1_2'] = r.dsize
  495. placeholders[f'v1_3'] = r.dsizeok
  496. placeholders[f'v2_2'] = r.tsize
  497. placeholders[f'v2_3'] = r.tsizeok
  498. placeholders[f'v3_2'] = r.hsize
  499. placeholders[f'v3_3'] = r.hsizeok
  500. # if is_ok(r):
  501. # placeholders[f'v4_1'] = 'OK'
  502. # placeholders[f'v4_2'] = 'OK'
  503. # else:
  504. # placeholders[f'v4_1'] = 'NG'
  505. # placeholders[f'v4_2'] = 'OK'
  506. if r.row_no == 2:
  507. placeholders[f'v10_2'] = r.dsize
  508. placeholders[f'v10_3'] = r.dsizeok
  509. placeholders[f'v11_2'] = r.tsize
  510. placeholders[f'v11_3'] = r.tsizeok
  511. placeholders[f'v12_2'] = r.hsize
  512. placeholders[f'v12_3'] = r.hsizeok
  513. # if is_ok(r):
  514. # placeholders[f'v8_1'] = 'OK'
  515. # placeholders[f'v8_2'] = 'OK'
  516. # else:
  517. # placeholders[f'v8_1'] = 'NG'
  518. # placeholders[f'v8_2'] = 'NG'
  519. for r in data_wb:
  520. if r.row_no == 1:
  521. placeholders["v4_2"] = r.weight
  522. placeholders["v4_3"] = r.judgement
  523. if r.row_no == 2:
  524. placeholders["v13_2"] = r.weight
  525. placeholders["v13_3"] = r.judgement
  526. for r in data_ho:
  527. if r.row_no == 1:
  528. rmap = {'OUT': 7, 'MID': 8, 'IN': 9}
  529. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  530. idx = rmap.get(r.r_type, None)
  531. if idx:
  532. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  533. if r.row_no == 2:
  534. rmap = {'OUT': 16, 'MID': 17, 'IN': 18}
  535. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  536. idx = rmap.get(r.r_type, None)
  537. if idx:
  538. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  539. for r in rotates:
  540. if r.row_no == 1:
  541. placeholders["v6_1"] = r.speed_spec
  542. placeholders["v6_2"] = r.speed_test
  543. placeholders["v6_3"] = r.speedok
  544. if r.row_no == 2:
  545. placeholders["v15_1"] = r.speed_spec
  546. placeholders["v15_2"] = r.speed_test
  547. placeholders["v15_3"] = r.speedok
  548. # hide_con(placeholders, "v5_1", "26:32")
  549. return placeholders
  550. def generate_centering_values(lot_no, code):
  551. """
  552. Fetch dimension records from manualSize and DataMs models
  553. and generate placeholder values for Standard, Actual, and Judgement.
  554. Supports two row_no entries per lot.
  555. """
  556. # Fetch standard values from manualSize (limit to 2 rows)
  557. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  558. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  559. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  560. # Prepare placeholders
  561. # placeholders = {}
  562. placeholders = clear_values(10,3)
  563. # for i in range(1,7):
  564. # for j in range(1,4):
  565. # placeholders[f'v{i}_{j}'] = 0
  566. pprint(placeholders)
  567. pprint(manual_size_records)
  568. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  569. for i,r in enumerate(data_ms_records, start=1):
  570. placeholders[f'v{i}_2'] = r.censize
  571. placeholders[f'v{i}_3'] = r.censizeok
  572. return placeholders
  573. def generate_t8_values(lot_no, code):
  574. """
  575. Fetch dimension records from manualSize and DataMs models
  576. and generate placeholder values for Standard, Actual, and Judgement.
  577. Supports two row_no entries per lot.
  578. """
  579. # Fetch standard values from manualSize (limit to 2 rows)
  580. placeholders = clear_values(8,10)
  581. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  582. # pprint(f"manual_size = {manual_size_records}")
  583. for m in manual_size_records:
  584. if m.size_name == "Thickness":
  585. for i in range(1,9):
  586. placeholders[f'v{i}_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  587. # pprint("set std")
  588. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  589. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  590. # Prepare placeholders
  591. # placeholders = {}
  592. # for i in range(1,7):
  593. # for j in range(1,4):
  594. # placeholders[f'v{i}_{j}'] = 0
  595. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  596. for i,r in enumerate(data_ms_records, start=1):
  597. placeholders[f'v{i}_2'] = r.tpoint1
  598. placeholders[f'v{i}_3'] = r.tpoint2
  599. placeholders[f'v{i}_4'] = r.tpoint3
  600. placeholders[f'v{i}_5'] = r.tpoint4
  601. placeholders[f'v{i}_10'] = r.tdiff
  602. return placeholders
  603. def merge_sheet_data_with_data(sheet_data, data):
  604. """
  605. Merge `sheet_data` with `data`.
  606. :param sheet_data: Dictionary containing the sheet-specific data.
  607. :param data: Dictionary containing general data.
  608. :return: A merged dictionary combining both `sheet_data` and `data`.
  609. """
  610. # Merge dictionaries using unpacking
  611. merged_data = {**data, **sheet_data}
  612. return merged_data
  613. def create_coi_file(lot_no, sheets, user, md):
  614. pprint("---- create_coi_file ---")
  615. pprint(md)
  616. qa1 = User.objects.get(pk=md['qa1'])
  617. qa2 = User.objects.get(pk=md['qa2'])
  618. accept = specialAccept = False
  619. if md['acceptStatus'] == "accepted":
  620. accept = True
  621. if md['acceptStatus'] == "special_accepted":
  622. specialAccept = True
  623. pprint(qa1)
  624. pprint(qa2)
  625. results = queryFromMaster(lot_no)
  626. first_result = results[0] if results else None
  627. code = first_result.PRO1 if first_result else None
  628. sheet_data = {}
  629. for sheet_name in sheets:
  630. if sheet_name == 'hardness_out':
  631. sheet_data[sheet_name] = generate_hardness_out_values(lot_no, code)
  632. elif sheet_name == 'hardness_out_in':
  633. sheet_data[sheet_name] = generate_hardness_out_in_values(lot_no, code)
  634. elif sheet_name == 'hardness_both_size':
  635. sheet_data[sheet_name] = generate_hardness_both_size_values(lot_no, first_result, code)
  636. elif sheet_name == 'dimension':
  637. sheet_data[sheet_name] = generate_dimension_values(lot_no, code)
  638. elif sheet_name == 'dimension_app':
  639. sheet_data[sheet_name] = generate_dimension_app_values(lot_no, code)
  640. elif sheet_name == 'dimension_bal_weight':
  641. sheet_data[sheet_name] = generate_dimension_bal_weight_values(lot_no, first_result, code)
  642. elif sheet_name == 'centering':
  643. sheet_data[sheet_name] = generate_centering_values(lot_no, code)
  644. elif sheet_name == 'thickness_8_point':
  645. sheet_data[sheet_name] = generate_t8_values(lot_no, code)
  646. elif sheet_name == 'dim_bal_app_hard':
  647. sheet_data[sheet_name] = generate_dim_bal_app_hard_values(lot_no, first_result, code)
  648. elif sheet_name == 'dim_bal_app_rot_hard':
  649. sheet_data[sheet_name] = generate_dim_bal_app_rot_hard_values(lot_no, first_result, code)
  650. converted_data = convert_sheet_data(sheet_data)
  651. print(f"sheet_data \n {sheet_data}")
  652. print(f"converted_data \n {converted_data}")
  653. # results = queryFromMaster(lot_no)
  654. # first_result = results[0] if results else None
  655. try:
  656. pcs = int(first_result.PRO5) - int(first_result.PRO27)
  657. except:
  658. pcs = 0
  659. if first_result:
  660. size_str = f"{first_result.PRO10}x{first_result.PRO11}x{first_result.PRO12}";
  661. spec = f"{first_result.PRO13} {first_result.PRO14} {first_result.PRO15} {first_result.PRO16} {first_result.PRO17} {first_result.PRO18}"
  662. else:
  663. size_str = ""
  664. spec = ""
  665. data = {
  666. "code": first_result.PRO1 if first_result else "-",
  667. "customer": first_result.PRO1C if first_result else "-",
  668. "inspect_date": "2025-01-15",
  669. "lot_no": lot_no,
  670. "size": size_str,
  671. "lot_size": pcs,
  672. "spec": spec,
  673. # "hardness_out.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  674. # "hardness_out.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  675. "acc": accept, # Hide rows 24 to 28 if the prefix is "0"
  676. "spe_acc": specialAccept, # Hide rows 24 to 28 if the prefix is "0"
  677. # "hardness_out.qa1": f"{qa1.first_name} {qa1.last_name}",
  678. # "hardness_out.qa2": f"{qa2.first_name} {qa2.last_name}",
  679. "qa1": f"{qa1.first_name} {qa1.last_name}",
  680. "qa2": f"{qa2.first_name} {qa2.last_name}",
  681. "sign1": qa1.profile.signed_picture,
  682. "sign2": qa2.profile.signed_picture,
  683. "pos1": qa1.profile.get_position_display(),
  684. "pos2": qa2.profile.get_position_display()
  685. }
  686. merged_data = merge_sheet_data_with_data(converted_data, data)
  687. pprint(f"---- merged_data ---")
  688. pprint(merged_data)
  689. output_file = gen_xlsx(
  690. template_file=f"{settings.BASE_DIR}/report/coi_templates.xlsx",
  691. selected_sheets=sheets, # Replace with your actual sheet names
  692. prefix_filename=f"{settings.BASE_DIR}/media/coi_{lot_no}_",
  693. data=merged_data
  694. )
  695. report = Report.objects.create(
  696. name=lot_no,
  697. created_by=user,
  698. file=None # Leave this as None or assign a file if required
  699. )
  700. output_file_path = Path(output_file) # Convert to a Path object for convenience
  701. with open(output_file_path, "rb") as f:
  702. report.file.save(output_file_path.name, File(f), save=True)
  703. pprint(f"outputfile = {output_file}")
  704. return report
  705. SHEET_NAMES = {
  706. 'hardness_out': 'Hardness Out',
  707. 'hardness_out_in': 'Hardness Out/In',
  708. 'hardness_both_size': 'Hardness Both Size',
  709. 'dimension': 'Dimension',
  710. 'dimension_app': 'Dimension Appearance',
  711. 'dimension_bal_weight': 'Dimension Balance/Weight',
  712. 'dim_bal_app_hard': 'Dimension Balance/Appearance/Hardness',
  713. 'dim_bal_app_rot_hard': 'Dimension Balance/Appearance/Rotation/Hardness',
  714. 'thickness_8_point': 'Thickness 8 Points',
  715. 'centering': 'Centering',
  716. }
  717. def get_fields(model):
  718. # model_fields = {f.name: f for f in model._meta.get_fields()}
  719. # fields = list(model_fields.values())
  720. # return fields
  721. fields = [f for f in model._meta.get_fields() if not f.auto_created]
  722. return fields
  723. def filter_by_lot_no(lot_no):
  724. models = [Data, DataMs, DataRl, DataWb, LotSummary, LotSummaryRl, LotSummaryWb, PressCal, RotateData ] # List of models to process
  725. results = {}
  726. fields = {}
  727. for model in models:
  728. model_fields = [f.name for f in model._meta.get_fields()]
  729. # Check if "id" and "row_no" are in the model's fields
  730. order_fields = []
  731. if "id" in model_fields:
  732. order_fields.append("id")
  733. if "row_no" in model_fields:
  734. order_fields.append("row_no")
  735. # Dynamically filter and order results
  736. model_name = model.__name__
  737. if order_fields:
  738. results[model_name] = model.objects.filter(lot_no=lot_no).order_by(*order_fields)
  739. else:
  740. results[model_name] = model.objects.filter(lot_no=lot_no) # No
  741. fields[model_name] = get_fields(model)
  742. return results, fields
  743. def coi_view(request):
  744. pprint(f"xxxx method = xxx {request.method}")
  745. users = User.objects.all()
  746. if request.method == "POST":
  747. pprint(request.POST)
  748. exports = request.POST.getlist("exports") # Retrieve the list of selected values
  749. pprint(f"Selected Export Options: {exports}")
  750. if 'export' in request.POST:
  751. data = {
  752. "customer": "Tum Coder",
  753. "inspect_date": "2025-01-15",
  754. "lot_no": "12345",
  755. "staff_name": "Tum 8888",
  756. "man_name": "Tum 999",
  757. "size": "Large",
  758. "lot_size": "10 pcs",
  759. "spec": "Spec-A",
  760. "hardness_out.d1_act": "10",
  761. "hardness_out.d2_act": "0[24:28]", # Hide rows 24 to 28 if the prefix is "0"
  762. "hardness_out.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  763. "hardness_out.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  764. "dimension_app.d1_act": "33",
  765. "dimension_app.d2_act": "0[26:32]", # Hide rows 24 to 28 if the prefix is "0"
  766. "dimension_app.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  767. "dimension_app.spe_acc": True, # Hide rows 24 to 28 if the prefix is "0"
  768. }
  769. output_file = gen_xlsx(
  770. template_file="/app/report/coi_templates.xlsx",
  771. selected_sheets=exports, # Replace with your actual sheet names
  772. prefix_filename="/app/media/coi",
  773. data=data
  774. )
  775. report = Report.objects.create(
  776. name=request.POST.get('lot_no','Untitled'),
  777. created_by=request.user,
  778. file=None # Leave this as None or assign a file if required
  779. )
  780. output_file_path = Path(output_file) # Convert to a Path object for convenience
  781. with open(output_file_path, "rb") as f:
  782. report.file.save(output_file_path.name, File(f), save=True)
  783. pprint(f"outputfile = {output_file}")
  784. if 'search_lot' in request.POST:
  785. lot_no = request.POST.get('lot_no', None)
  786. lot_no = lot_no.strip()
  787. if lot_no:
  788. results = queryFromMaster(lot_no)
  789. first_result = results[0] if results else None
  790. try:
  791. pcs = int(first_result.PRO5) - int(first_result.PRO27)
  792. except:
  793. pcs = 0
  794. if first_result:
  795. size_str = f"{first_result.PRO10}x{first_result.PRO11}x{first_result.PRO12}";
  796. spec = f"{first_result.PRO13} {first_result.PRO14} {first_result.PRO15} {first_result.PRO16} {first_result.PRO17} {first_result.PRO18}"
  797. else:
  798. size_str = ""
  799. spec = ""
  800. results, fields = filter_by_lot_no(lot_no)
  801. # results1 = Data.objects.filter(lot_no=lot_no).order_by("id", "row_no")
  802. # fields1 = get_fields(Data)
  803. # results2 = DataMs.objects.filter(lot_no=lot_no).order_by("id", "row_no")
  804. # fields2 = get_fields(DataMs)
  805. return render(request, 'report/coi.html', {'result': first_result,
  806. 'pcs':pcs,
  807. 'size_str': size_str,
  808. 'lot_no': lot_no,
  809. 'spec': spec, 'users': users, 'SHEET_NAMES': SHEET_NAMES,
  810. 'results': results, 'fields': fields})
  811. messages.success(request, "Request Sent")
  812. return redirect(request.path_info)
  813. return render(request, 'report/coi.html', {'SHEET_NAMES': SHEET_NAMES, 'users': users})
  814. @csrf_exempt # Disable CSRF for API requests (ensure this is secure in production)
  815. @login_required
  816. def gen_report_view(request):
  817. if request.method == "POST":
  818. # try:
  819. # Parse JSON data from the request body
  820. data = json.loads(request.body)
  821. lot_no = data.get("lot_no").strip()
  822. exports = data.get("exports")
  823. qa1 = data.get('qa1')
  824. qa2 = data.get('qa2')
  825. print(f"data = {data}")
  826. if not lot_no:
  827. return HttpResponseBadRequest("Missing 'lot_no' in request data")
  828. # Call the `create_coi_file` function with the provided lot_no
  829. report = create_coi_file(lot_no, exports, request.user, {'qa1': qa1, 'qa2': qa2, \
  830. 'acceptStatus': data.get('acceptStatus')})
  831. # Return a success response with the report details
  832. return JsonResponse({
  833. "message": "Report generated successfully",
  834. "report_id": report.id,
  835. "file_url": report.file.url if report.file else None,
  836. })
  837. # except json.JSONDecodeError:
  838. # return HttpResponseBadRequest("Invalid JSON data")
  839. # except Exception as e:
  840. # pprint(e)
  841. # return JsonResponse({"error": str(e)}, status=500)
  842. else:
  843. return HttpResponseBadRequest("Only POST requests are allowed")