暂无描述

views.py 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  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
  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 generate_hardness_out_values(lot_no):
  88. """
  89. Generate a dictionary of placeholder values for a given lot_no.
  90. :param lot_no: The lot number to query data for.
  91. :return: A dictionary with placeholders (e.g., v1_1, v1_2, ...) as keys and their respective values.
  92. """
  93. # Query the Data model for records matching the given lot_no
  94. records = Data.objects.filter(lot_no=lot_no).order_by('row_no')
  95. print(f"records {lot_no} = {records.values()}")
  96. # Initialize an empty dictionary to store placeholder values
  97. placeholders = {}
  98. # Iterate over the records to populate placeholder values
  99. for record_idx, record in enumerate(records, start=1):
  100. placeholders[f'v{record_idx}_1'] = record.p1 # Checkpoint 1 value
  101. placeholders[f'v{record_idx}_2'] = record.p2 # Checkpoint 2 value
  102. placeholders[f'v{record_idx}_3'] = record.p3 # Checkpoint 3 value
  103. placeholders[f'v{record_idx}_4'] = record.avg # Average value
  104. placeholders[f'v{record_idx}_5'] = record.rgrade # Judgment value
  105. return placeholders
  106. def generate_hardness_out_in_values(lot_no):
  107. # Fetch records from the Data model
  108. records = Data.objects.filter(lot_no=lot_no).order_by('row_no')
  109. out_data = []
  110. in_data = []
  111. # Separate OUT and IN data
  112. for record in records:
  113. if record.r_type.upper() in ["OUT", "TOP", "FA1", "UPP", "UPPE", "RIM"]:
  114. out_data.append(record)
  115. elif record.r_type.upper() in ["IN", "UNDER", "UND", "FA2", "LOW", "LOWE", "BASE", "SOKO", "IN*"]:
  116. in_data.append(record)
  117. # Prepare placeholders
  118. placeholders = {}
  119. for idx, record in enumerate(out_data, start=1):
  120. placeholders[f'v{idx}_1'] = record.p1
  121. placeholders[f'v{idx}_2'] = record.p2
  122. placeholders[f'v{idx}_3'] = record.p3
  123. placeholders[f'v{idx}_4'] = record.avg
  124. placeholders[f'v{idx}_5'] = record.rgrade
  125. for idx, record in enumerate(in_data, start=1):
  126. placeholders[f'v{len(out_data) + idx}_1'] = record.p1
  127. placeholders[f'v{len(out_data) + idx}_2'] = record.p2
  128. placeholders[f'v{len(out_data) + idx}_3'] = record.p3
  129. placeholders[f'v{len(out_data) + idx}_4'] = record.avg
  130. placeholders[f'v{len(out_data) + idx}_5'] = record.rgrade
  131. # if "v3_1" in placeholders:
  132. # placeholders["v3_1"] = f"{placeholders['v3_1']}[25:28]"
  133. # else:
  134. # placeholders[f"v3_1"] = "0[25:28]"
  135. hide_con(placeholders, "v3_1", "25:28")
  136. return placeholders
  137. def clear_values(n, m):
  138. placeholders = {}
  139. for i in range(1, n + 1):
  140. for j in range(1, m + 1):
  141. placeholders[f'v{i}_{j}'] = " "
  142. return placeholders
  143. # # Example usage:
  144. # placeholders_dict = clear_values(6, 3)
  145. # print(placeholders_dict)
  146. def generate_dimension_values(lot_no):
  147. """
  148. Fetch dimension records from manualSize and DataMs models
  149. and generate placeholder values for Standard, Actual, and Judgement.
  150. Supports two row_no entries per lot.
  151. """
  152. # Fetch standard values from manualSize (limit to 2 rows)
  153. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  154. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  155. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')[:2]
  156. # Prepare placeholders
  157. # placeholders = {}
  158. placeholders = clear_values(7,4)
  159. # for i in range(1,7):
  160. # for j in range(1,4):
  161. # placeholders[f'v{i}_{j}'] = 0
  162. pprint(placeholders)
  163. pprint(manual_size_records)
  164. for m in manual_size_records:
  165. if m.size_name == "D":
  166. placeholders['v1_1'] = placeholders['v4_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  167. if m.size_name == "T":
  168. placeholders['v2_1'] = placeholders['v5_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  169. if m.size_name == "H":
  170. placeholders['v3_1'] = placeholders['v6_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  171. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  172. for r in data_ms_records:
  173. if r.row_no == 1:
  174. placeholders[f'v1_2'] = r.dsize
  175. placeholders[f'v1_3'] = r.dsizeok
  176. placeholders[f'v2_2'] = r.tsize
  177. placeholders[f'v2_3'] = r.tsizeok
  178. placeholders[f'v3_2'] = r.hsize
  179. placeholders[f'v3_3'] = r.hsizeok
  180. if r.row_no == 2:
  181. placeholders[f'v4_2'] = r.dsize
  182. placeholders[f'v4_3'] = r.dsizeok
  183. placeholders[f'v5_2'] = r.tsize
  184. placeholders[f'v5_3'] = r.tsizeok
  185. placeholders[f'v6_2'] = r.hsize
  186. placeholders[f'v6_3'] = r.hsizeok
  187. hide_con(placeholders, "v4_2", "24:28")
  188. return placeholders
  189. def is_ok(instance):
  190. fields_and_values = {}
  191. for field in instance._meta.get_fields():
  192. field_name = field.name
  193. if field_name.endswith('ok'):
  194. v = getattr(instance, field_name)
  195. if v is not None and v != "OK":
  196. return False
  197. return True
  198. def generate_dimension_app_values(lot_no):
  199. """
  200. Fetch dimension records from manualSize and DataMs models
  201. and generate placeholder values for Standard, Actual, and Judgement.
  202. Supports two row_no entries per lot.
  203. """
  204. # Fetch standard values from manualSize (limit to 2 rows)
  205. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  206. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  207. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')[:2]
  208. # Prepare placeholders
  209. # placeholders = {}
  210. placeholders = clear_values(8,3)
  211. # for i in range(1,7):
  212. # for j in range(1,4):
  213. # placeholders[f'v{i}_{j}'] = 0
  214. pprint(placeholders)
  215. pprint(manual_size_records)
  216. for m in manual_size_records:
  217. if m.size_name == "D":
  218. placeholders['v1_1'] = placeholders['v5_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  219. if m.size_name == "T":
  220. placeholders['v2_1'] = placeholders['v6_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  221. if m.size_name == "H":
  222. placeholders['v3_1'] = placeholders['v7_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  223. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  224. for r in data_ms_records:
  225. if r.row_no == 1:
  226. placeholders[f'v1_2'] = r.dsize
  227. placeholders[f'v1_3'] = r.dsizeok
  228. placeholders[f'v2_2'] = r.tsize
  229. placeholders[f'v2_3'] = r.tsizeok
  230. placeholders[f'v3_2'] = r.hsize
  231. placeholders[f'v3_3'] = r.hsizeok
  232. # if is_ok(r):
  233. # placeholders[f'v4_1'] = 'OK'
  234. # placeholders[f'v4_2'] = 'OK'
  235. # else:
  236. # placeholders[f'v4_1'] = 'NG'
  237. # placeholders[f'v4_2'] = 'OK'
  238. if r.row_no == 2:
  239. placeholders[f'v5_2'] = r.dsize
  240. placeholders[f'v5_3'] = r.dsizeok
  241. placeholders[f'v6_2'] = r.tsize
  242. placeholders[f'v6_3'] = r.tsizeok
  243. placeholders[f'v7_2'] = r.hsize
  244. placeholders[f'v7_3'] = r.hsizeok
  245. # if is_ok(r):
  246. # placeholders[f'v8_1'] = 'OK'
  247. # placeholders[f'v8_2'] = 'OK'
  248. # else:
  249. # placeholders[f'v8_1'] = 'NG'
  250. # placeholders[f'v8_2'] = 'NG'
  251. hide_con(placeholders, "v5_1", "26:32")
  252. return placeholders
  253. def generate_dim_bal_app_hard_values(lot_no, first_result):
  254. """
  255. Fetch dimension records from manualSize and DataMs models
  256. and generate placeholder values for Standard, Actual, and Judgement.
  257. Supports two row_no entries per lot.
  258. """
  259. # Fetch standard values from manualSize (limit to 2 rows)
  260. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  261. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  262. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')[:2]
  263. data_wb = DataWb.objects.filter(lot_no=lot_no).order_by('row_no')[:2]
  264. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no')[:2])
  265. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no')[:2])
  266. data_ho = list(chain(data_h1, data_h2))
  267. if first_result:
  268. out_limit = f"Out 外 ({first_result.MI18} - {first_result.MI19})"
  269. in_limit = f"In 内 ({first_result.MI22} - {first_result.MI23})"
  270. mid_limit = f"Middle 中 -"
  271. else:
  272. out_limit = f"Out 外"
  273. in_limit = f"In 内"
  274. mid_limit = f"Middle 中"
  275. # Prepare placeholders
  276. # placeholders = {}
  277. placeholders = clear_values(16,5)
  278. # for i in range(1,7):
  279. # for j in range(1,4):
  280. # placeholders[f'v{i}_{j}'] = 0
  281. placeholders['v6_0'] = placeholders['v14_0'] = out_limit
  282. placeholders['v7_0'] = placeholders['v15_0'] = mid_limit
  283. placeholders['v18_0'] = placeholders['v16_0'] = in_limit
  284. pprint(placeholders)
  285. pprint(manual_size_records)
  286. if first_result:
  287. w = first_result.PRO6
  288. placeholders['v4_1'] = placeholders['v12_1'] = w
  289. for m in manual_size_records:
  290. if m.size_name == "D":
  291. placeholders['v1_1'] = placeholders['v9_1'] = f'D{m.std} +{m.tolup} {m.tolun}'
  292. if m.size_name == "T":
  293. placeholders['v2_1'] = placeholders['v10_1'] = f'T{m.std} +{m.tolup} {m.tolun}'
  294. if m.size_name == "H":
  295. placeholders['v3_1'] = placeholders['v11_1'] = f'H{m.std} +{m.tolup} {m.tolun}'
  296. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  297. for r in data_ms_records:
  298. if r.row_no == 1:
  299. placeholders[f'v1_2'] = r.dsize
  300. placeholders[f'v1_3'] = r.dsizeok
  301. placeholders[f'v2_2'] = r.tsize
  302. placeholders[f'v2_3'] = r.tsizeok
  303. placeholders[f'v3_2'] = r.hsize
  304. placeholders[f'v3_3'] = r.hsizeok
  305. # if is_ok(r):
  306. # placeholders[f'v4_1'] = 'OK'
  307. # placeholders[f'v4_2'] = 'OK'
  308. # else:
  309. # placeholders[f'v4_1'] = 'NG'
  310. # placeholders[f'v4_2'] = 'OK'
  311. if r.row_no == 2:
  312. placeholders[f'v9_2'] = r.dsize
  313. placeholders[f'v9_3'] = r.dsizeok
  314. placeholders[f'v10_2'] = r.tsize
  315. placeholders[f'v10_3'] = r.tsizeok
  316. placeholders[f'v11_2'] = r.hsize
  317. placeholders[f'v11_3'] = r.hsizeok
  318. # if is_ok(r):
  319. # placeholders[f'v8_1'] = 'OK'
  320. # placeholders[f'v8_2'] = 'OK'
  321. # else:
  322. # placeholders[f'v8_1'] = 'NG'
  323. # placeholders[f'v8_2'] = 'NG'
  324. for r in data_wb:
  325. if r.row_no == 1:
  326. placeholders["v4_2"] = r.weight
  327. placeholders["v4_3"] = r.judgement
  328. if r.row_no == 2:
  329. placeholders["v12_2"] = r.weight
  330. placeholders["v12_3"] = r.judgement
  331. for r in data_ho:
  332. if r.row_no == 1:
  333. rmap = {'OUT': 6, 'MID': 7, 'IN': 8}
  334. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  335. idx = rmap.get(r.r_type, None)
  336. if idx:
  337. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  338. if r.row_no == 2:
  339. rmap = {'OUT': 14, 'MID': 15, 'IN': 16}
  340. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  341. idx = rmap.get(r.r_type, None)
  342. if idx:
  343. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  344. # hide_con(placeholders, "v5_1", "26:32")
  345. return placeholders
  346. def generate_centering_values(lot_no):
  347. """
  348. Fetch dimension records from manualSize and DataMs models
  349. and generate placeholder values for Standard, Actual, and Judgement.
  350. Supports two row_no entries per lot.
  351. """
  352. # Fetch standard values from manualSize (limit to 2 rows)
  353. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  354. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  355. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')[:2]
  356. # Prepare placeholders
  357. # placeholders = {}
  358. placeholders = clear_values(10,3)
  359. # for i in range(1,7):
  360. # for j in range(1,4):
  361. # placeholders[f'v{i}_{j}'] = 0
  362. pprint(placeholders)
  363. pprint(manual_size_records)
  364. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  365. for i,r in enumerate(data_ms_records, start=1):
  366. placeholders[f'v{i}_2'] = r.censize
  367. placeholders[f'v{i}_3'] = r.censizeok
  368. return placeholders
  369. def generate_t8_values(lot_no):
  370. """
  371. Fetch dimension records from manualSize and DataMs models
  372. and generate placeholder values for Standard, Actual, and Judgement.
  373. Supports two row_no entries per lot.
  374. """
  375. # Fetch standard values from manualSize (limit to 2 rows)
  376. placeholders = clear_values(8,10)
  377. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  378. # pprint(f"manual_size = {manual_size_records}")
  379. for m in manual_size_records:
  380. if m.size_name == "Thickness":
  381. for i in range(1,9):
  382. placeholders[f'v{i}_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  383. # pprint("set std")
  384. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  385. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  386. # Prepare placeholders
  387. # placeholders = {}
  388. # for i in range(1,7):
  389. # for j in range(1,4):
  390. # placeholders[f'v{i}_{j}'] = 0
  391. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  392. for i,r in enumerate(data_ms_records, start=1):
  393. placeholders[f'v{i}_2'] = r.tpoint1
  394. placeholders[f'v{i}_3'] = r.tpoint2
  395. placeholders[f'v{i}_4'] = r.tpoint3
  396. placeholders[f'v{i}_5'] = r.tpoint4
  397. placeholders[f'v{i}_10'] = r.tdiff
  398. return placeholders
  399. def merge_sheet_data_with_data(sheet_data, data):
  400. """
  401. Merge `sheet_data` with `data`.
  402. :param sheet_data: Dictionary containing the sheet-specific data.
  403. :param data: Dictionary containing general data.
  404. :return: A merged dictionary combining both `sheet_data` and `data`.
  405. """
  406. # Merge dictionaries using unpacking
  407. merged_data = {**data, **sheet_data}
  408. return merged_data
  409. def create_coi_file(lot_no, sheets, user, md):
  410. pprint("---- create_coi_file ---")
  411. pprint(md)
  412. qa1 = User.objects.get(pk=md['qa1'])
  413. qa2 = User.objects.get(pk=md['qa2'])
  414. accept = specialAccept = False
  415. if md['acceptStatus'] == "accepted":
  416. accept = True
  417. if md['acceptStatus'] == "special_accepted":
  418. specialAccept = True
  419. pprint(qa1)
  420. pprint(qa2)
  421. results = queryFromMaster(lot_no)
  422. first_result = results[0] if results else None
  423. sheet_data = {}
  424. for sheet_name in sheets:
  425. match sheet_name:
  426. case 'hardness_out':
  427. sheet_data[sheet_name] = generate_hardness_out_values(lot_no)
  428. case 'hardness_out_in':
  429. sheet_data[sheet_name] = generate_hardness_out_in_values(lot_no)
  430. case 'dimension':
  431. sheet_data[sheet_name] = generate_dimension_values(lot_no)
  432. case 'dimension_app':
  433. sheet_data[sheet_name] = generate_dimension_app_values(lot_no)
  434. case 'centering':
  435. sheet_data[sheet_name] = generate_centering_values(lot_no)
  436. case 'centering':
  437. sheet_data[sheet_name] = generate_centering_values(lot_no)
  438. case 'thickness_8_point':
  439. sheet_data[sheet_name] = generate_t8_values(lot_no)
  440. case 'dim_bal_app_hard':
  441. sheet_data[sheet_name] = generate_dim_bal_app_hard_values(lot_no, first_result)
  442. converted_data = convert_sheet_data(sheet_data)
  443. print(f"sheet_data \n {sheet_data}")
  444. print(f"converted_data \n {converted_data}")
  445. # results = queryFromMaster(lot_no)
  446. # first_result = results[0] if results else None
  447. try:
  448. pcs = int(first_result.PRO5) - int(first_result.PRO27)
  449. except:
  450. pcs = 0
  451. if first_result:
  452. size_str = f"{first_result.PRO10}x{first_result.PRO11}x{first_result.PRO12}";
  453. spec = f"{first_result.PRO13} {first_result.PRO14} {first_result.PRO15} {first_result.PRO16} {first_result.PRO17} {first_result.PRO18}"
  454. else:
  455. size_str = ""
  456. spec = ""
  457. data = {
  458. "code": first_result.PRO1 if first_result else "-",
  459. "customer": first_result.PRO1C if first_result else "-",
  460. "inspect_date": "2025-01-15",
  461. "lot_no": lot_no,
  462. "size": size_str,
  463. "lot_size": pcs,
  464. "spec": spec,
  465. # "hardness_out.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  466. # "hardness_out.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  467. "acc": accept, # Hide rows 24 to 28 if the prefix is "0"
  468. "spe_acc": specialAccept, # Hide rows 24 to 28 if the prefix is "0"
  469. # "hardness_out.qa1": f"{qa1.first_name} {qa1.last_name}",
  470. # "hardness_out.qa2": f"{qa2.first_name} {qa2.last_name}",
  471. "qa1": f"{qa1.first_name} {qa1.last_name}",
  472. "qa2": f"{qa2.first_name} {qa2.last_name}",
  473. "sign1": qa1.profile.signed_picture,
  474. "sign2": qa2.profile.signed_picture,
  475. "pos1": qa1.profile.get_position_display(),
  476. "pos2": qa2.profile.get_position_display()
  477. }
  478. merged_data = merge_sheet_data_with_data(converted_data, data)
  479. pprint(f"---- merged_data ---")
  480. pprint(merged_data)
  481. output_file = gen_xlsx(
  482. template_file=f"{settings.BASE_DIR}/report/coi_templates.xlsx",
  483. selected_sheets=sheets, # Replace with your actual sheet names
  484. prefix_filename=f"{settings.BASE_DIR}/media/coi_{lot_no}_",
  485. data=merged_data
  486. )
  487. report = Report.objects.create(
  488. name=lot_no,
  489. created_by=user,
  490. file=None # Leave this as None or assign a file if required
  491. )
  492. output_file_path = Path(output_file) # Convert to a Path object for convenience
  493. with open(output_file_path, "rb") as f:
  494. report.file.save(output_file_path.name, File(f), save=True)
  495. pprint(f"outputfile = {output_file}")
  496. return report
  497. SHEET_NAMES = {
  498. 'hardness_out': 'Hardness Out',
  499. 'hardness_out_in': 'Hardness Out/In',
  500. 'hardness_both_size': 'Hardness Both Size',
  501. 'dimension': 'Dimension',
  502. 'dimension_app': 'Dimension Appearance',
  503. 'dimension_bal_weight': 'Dimension Balance/Weight',
  504. 'dim_bal_app_hard': 'Dimension Balance/Appearance/Hardness',
  505. 'dim_bal_app_rot_hard': 'Dimension Balance/Appearance/Rotation/Hardness',
  506. 'thickness_8_point': 'Thickness 8 Points',
  507. 'centering': 'Centering',
  508. }
  509. def get_fields(model):
  510. # model_fields = {f.name: f for f in model._meta.get_fields()}
  511. # fields = list(model_fields.values())
  512. # return fields
  513. fields = [f for f in model._meta.get_fields() if not f.auto_created]
  514. return fields
  515. def filter_by_lot_no(lot_no):
  516. models = [Data, DataMs, DataRl, DataWb, LotSummary, LotSummaryRl, LotSummaryWb, PressCal, RotateData ] # List of models to process
  517. results = {}
  518. fields = {}
  519. for model in models:
  520. model_fields = [f.name for f in model._meta.get_fields()]
  521. # Check if "id" and "row_no" are in the model's fields
  522. order_fields = []
  523. if "id" in model_fields:
  524. order_fields.append("id")
  525. if "row_no" in model_fields:
  526. order_fields.append("row_no")
  527. # Dynamically filter and order results
  528. model_name = model.__name__
  529. if order_fields:
  530. results[model_name] = model.objects.filter(lot_no=lot_no).order_by(*order_fields)
  531. else:
  532. results[model_name] = model.objects.filter(lot_no=lot_no) # No
  533. fields[model_name] = get_fields(model)
  534. return results, fields
  535. def coi_view(request):
  536. pprint(f"xxxx method = xxx {request.method}")
  537. users = User.objects.all()
  538. if request.method == "POST":
  539. pprint(request.POST)
  540. exports = request.POST.getlist("exports") # Retrieve the list of selected values
  541. pprint(f"Selected Export Options: {exports}")
  542. if 'export' in request.POST:
  543. data = {
  544. "customer": "Tum Coder",
  545. "inspect_date": "2025-01-15",
  546. "lot_no": "12345",
  547. "staff_name": "Tum 8888",
  548. "man_name": "Tum 999",
  549. "size": "Large",
  550. "lot_size": "10 pcs",
  551. "spec": "Spec-A",
  552. "hardness_out.d1_act": "10",
  553. "hardness_out.d2_act": "0[24:28]", # Hide rows 24 to 28 if the prefix is "0"
  554. "hardness_out.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  555. "hardness_out.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  556. "dimension_app.d1_act": "33",
  557. "dimension_app.d2_act": "0[26:32]", # Hide rows 24 to 28 if the prefix is "0"
  558. "dimension_app.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  559. "dimension_app.spe_acc": True, # Hide rows 24 to 28 if the prefix is "0"
  560. }
  561. output_file = gen_xlsx(
  562. template_file="/app/report/coi_templates.xlsx",
  563. selected_sheets=exports, # Replace with your actual sheet names
  564. prefix_filename="/app/media/coi",
  565. data=data
  566. )
  567. report = Report.objects.create(
  568. name=request.POST.get('lot_no','Untitled'),
  569. created_by=request.user,
  570. file=None # Leave this as None or assign a file if required
  571. )
  572. output_file_path = Path(output_file) # Convert to a Path object for convenience
  573. with open(output_file_path, "rb") as f:
  574. report.file.save(output_file_path.name, File(f), save=True)
  575. pprint(f"outputfile = {output_file}")
  576. if 'search_lot' in request.POST:
  577. lot_no = request.POST.get('lot_no', None)
  578. lot_no = lot_no.strip()
  579. if lot_no:
  580. results = queryFromMaster(lot_no)
  581. first_result = results[0] if results else None
  582. try:
  583. pcs = int(first_result.PRO5) - int(first_result.PRO27)
  584. except:
  585. pcs = 0
  586. if first_result:
  587. size_str = f"{first_result.PRO10}x{first_result.PRO11}x{first_result.PRO12}";
  588. spec = f"{first_result.PRO13} {first_result.PRO14} {first_result.PRO15} {first_result.PRO16} {first_result.PRO17} {first_result.PRO18}"
  589. else:
  590. size_str = ""
  591. spec = ""
  592. results, fields = filter_by_lot_no(lot_no)
  593. # results1 = Data.objects.filter(lot_no=lot_no).order_by("id", "row_no")
  594. # fields1 = get_fields(Data)
  595. # results2 = DataMs.objects.filter(lot_no=lot_no).order_by("id", "row_no")
  596. # fields2 = get_fields(DataMs)
  597. return render(request, 'report/coi.html', {'result': first_result,
  598. 'pcs':pcs,
  599. 'size_str': size_str,
  600. 'lot_no': lot_no,
  601. 'spec': spec, 'users': users, 'SHEET_NAMES': SHEET_NAMES,
  602. 'results': results, 'fields': fields})
  603. messages.success(request, "Request Sent")
  604. return redirect(request.path_info)
  605. return render(request, 'report/coi.html', {'SHEET_NAMES': SHEET_NAMES, 'users': users})
  606. @csrf_exempt # Disable CSRF for API requests (ensure this is secure in production)
  607. @login_required
  608. def gen_report_view(request):
  609. if request.method == "POST":
  610. # try:
  611. # Parse JSON data from the request body
  612. data = json.loads(request.body)
  613. lot_no = data.get("lot_no").strip()
  614. exports = data.get("exports")
  615. qa1 = data.get('qa1')
  616. qa2 = data.get('qa2')
  617. print(f"data = {data}")
  618. if not lot_no:
  619. return HttpResponseBadRequest("Missing 'lot_no' in request data")
  620. # Call the `create_coi_file` function with the provided lot_no
  621. report = create_coi_file(lot_no, exports, request.user, {'qa1': qa1, 'qa2': qa2, \
  622. 'acceptStatus': data.get('acceptStatus')})
  623. # Return a success response with the report details
  624. return JsonResponse({
  625. "message": "Report generated successfully",
  626. "report_id": report.id,
  627. "file_url": report.file.url if report.file else None,
  628. })
  629. # except json.JSONDecodeError:
  630. # return HttpResponseBadRequest("Invalid JSON data")
  631. # except Exception as e:
  632. # pprint(e)
  633. # return JsonResponse({"error": str(e)}, status=500)
  634. else:
  635. return HttpResponseBadRequest("Only POST requests are allowed")