暫無描述

views.py 38KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  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 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):
  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):
  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):
  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):
  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. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  182. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  183. # Prepare placeholders
  184. # placeholders = {}
  185. placeholders = clear_values(7,4)
  186. # for i in range(1,7):
  187. # for j in range(1,4):
  188. # placeholders[f'v{i}_{j}'] = 0
  189. pprint(placeholders)
  190. pprint(manual_size_records)
  191. for m in manual_size_records:
  192. if m.size_name == "D":
  193. placeholders['v1_1'] = placeholders['v4_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  194. if m.size_name == "T":
  195. placeholders['v2_1'] = placeholders['v5_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  196. if m.size_name == "H":
  197. placeholders['v3_1'] = placeholders['v6_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  198. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  199. for r in data_ms_records:
  200. if r.row_no == 1:
  201. placeholders[f'v1_2'] = r.dsize
  202. placeholders[f'v1_3'] = r.dsizeok
  203. placeholders[f'v2_2'] = r.tsize
  204. placeholders[f'v2_3'] = r.tsizeok
  205. placeholders[f'v3_2'] = r.hsize
  206. placeholders[f'v3_3'] = r.hsizeok
  207. if r.row_no == 2:
  208. placeholders[f'v4_2'] = r.dsize
  209. placeholders[f'v4_3'] = r.dsizeok
  210. placeholders[f'v5_2'] = r.tsize
  211. placeholders[f'v5_3'] = r.tsizeok
  212. placeholders[f'v6_2'] = r.hsize
  213. placeholders[f'v6_3'] = r.hsizeok
  214. hide_con(placeholders, "v4_1", "24:28")
  215. return placeholders
  216. def is_ok(instance):
  217. fields_and_values = {}
  218. for field in instance._meta.get_fields():
  219. field_name = field.name
  220. if field_name.endswith('ok'):
  221. v = getattr(instance, field_name)
  222. if v is not None and v != "OK":
  223. return False
  224. return True
  225. def generate_dimension_app_values(lot_no):
  226. """
  227. Fetch dimension records from manualSize and DataMs models
  228. and generate placeholder values for Standard, Actual, and Judgement.
  229. Supports two row_no entries per lot.
  230. """
  231. # Fetch standard values from manualSize (limit to 2 rows)
  232. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  233. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  234. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  235. # Prepare placeholders
  236. # placeholders = {}
  237. placeholders = clear_values(8,3)
  238. # for i in range(1,7):
  239. # for j in range(1,4):
  240. # placeholders[f'v{i}_{j}'] = 0
  241. pprint(placeholders)
  242. pprint(manual_size_records)
  243. for m in manual_size_records:
  244. if m.size_name == "D":
  245. placeholders['v1_1'] = placeholders['v5_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  246. if m.size_name == "T":
  247. placeholders['v2_1'] = placeholders['v6_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  248. if m.size_name == "H":
  249. placeholders['v3_1'] = placeholders['v7_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  250. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  251. for r in data_ms_records:
  252. if r.row_no == 1:
  253. placeholders[f'v1_2'] = r.dsize
  254. placeholders[f'v1_3'] = r.dsizeok
  255. placeholders[f'v2_2'] = r.tsize
  256. placeholders[f'v2_3'] = r.tsizeok
  257. placeholders[f'v3_2'] = r.hsize
  258. placeholders[f'v3_3'] = r.hsizeok
  259. # if is_ok(r):
  260. # placeholders[f'v4_1'] = 'OK'
  261. # placeholders[f'v4_2'] = 'OK'
  262. # else:
  263. # placeholders[f'v4_1'] = 'NG'
  264. # placeholders[f'v4_2'] = 'OK'
  265. if r.row_no == 2:
  266. placeholders[f'v5_2'] = r.dsize
  267. placeholders[f'v5_3'] = r.dsizeok
  268. placeholders[f'v6_2'] = r.tsize
  269. placeholders[f'v6_3'] = r.tsizeok
  270. placeholders[f'v7_2'] = r.hsize
  271. placeholders[f'v7_3'] = r.hsizeok
  272. # if is_ok(r):
  273. # placeholders[f'v8_1'] = 'OK'
  274. # placeholders[f'v8_2'] = 'OK'
  275. # else:
  276. # placeholders[f'v8_1'] = 'NG'
  277. # placeholders[f'v8_2'] = 'NG'
  278. hide_con(placeholders, "v5_1", "26:32")
  279. return placeholders
  280. def generate_dimension_bal_weight_values(lot_no, ms):
  281. """
  282. Fetch dimension records from manualSize and DataMs models
  283. and generate placeholder values for Standard, Actual, and Judgement.
  284. Supports two row_no entries per lot.
  285. """
  286. # Fetch standard values from manualSize (limit to 2 rows)
  287. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  288. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  289. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  290. data_wb = DataWb.objects.filter(lot_no=lot_no).order_by('row_no')
  291. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no'))
  292. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no'))
  293. data_ho = list(chain(data_h1, data_h2))
  294. # Prepare placeholders
  295. # placeholders = {}
  296. placeholders = clear_values(10,3)
  297. # for i in range(1,7):
  298. # for j in range(1,4):
  299. # placeholders[f'v{i}_{j}'] = 0
  300. pprint(placeholders)
  301. pprint(manual_size_records)
  302. if ms:
  303. w = ms.PRO6
  304. placeholders['v4_1'] = placeholders['v9_1'] = w
  305. for m in manual_size_records:
  306. if m.size_name == "D":
  307. placeholders['v1_1'] = placeholders['v6_1'] = f'D{m.std} +{m.tolup} {m.tolun}'
  308. if m.size_name == "T":
  309. placeholders['v2_1'] = placeholders['v7_1'] = f'T{m.std} +{m.tolup} {m.tolun}'
  310. if m.size_name == "H":
  311. placeholders['v3_1'] = placeholders['v8_1'] = f'H{m.std} +{m.tolup} {m.tolun}'
  312. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  313. for r in data_ms_records:
  314. if r.row_no == 1:
  315. placeholders[f'v1_2'] = r.dsize
  316. placeholders[f'v1_3'] = r.dsizeok
  317. placeholders[f'v2_2'] = r.tsize
  318. placeholders[f'v2_3'] = r.tsizeok
  319. placeholders[f'v3_2'] = r.hsize
  320. placeholders[f'v3_3'] = r.hsizeok
  321. # if is_ok(r):
  322. # placeholders[f'v4_1'] = 'OK'
  323. # placeholders[f'v4_2'] = 'OK'
  324. # else:
  325. # placeholders[f'v4_1'] = 'NG'
  326. # placeholders[f'v4_2'] = 'OK'
  327. if r.row_no == 2:
  328. placeholders[f'v6_2'] = r.dsize
  329. placeholders[f'v6_3'] = r.dsizeok
  330. placeholders[f'v7_2'] = r.tsize
  331. placeholders[f'v7_3'] = r.tsizeok
  332. placeholders[f'v8_2'] = r.hsize
  333. placeholders[f'v8_3'] = r.hsizeok
  334. # if is_ok(r):
  335. # placeholders[f'v8_1'] = 'OK'
  336. # placeholders[f'v8_2'] = 'OK'
  337. # else:
  338. # placeholders[f'v8_1'] = 'NG'
  339. # placeholders[f'v8_2'] = 'NG'
  340. for r in data_wb:
  341. if r.row_no == 1:
  342. placeholders["v4_2"] = r.result
  343. placeholders["v4_3"] = r.judgement
  344. placeholders["v5_2"] = r.weight
  345. placeholders["v5_3"] = r.judgement
  346. if r.row_no == 2:
  347. placeholders["v9_2"] = r.result
  348. placeholders["v9_3"] = r.judgement
  349. placeholders["v10_2"] = r.weight
  350. placeholders["v10_3"] = r.judgement
  351. # hide_con(placeholders, "v5_1", "26:32")
  352. return placeholders
  353. def generate_dim_bal_app_hard_values(lot_no, first_result):
  354. """
  355. Fetch dimension records from manualSize and DataMs models
  356. and generate placeholder values for Standard, Actual, and Judgement.
  357. Supports two row_no entries per lot.
  358. """
  359. # Fetch standard values from manualSize (limit to 2 rows)
  360. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  361. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  362. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  363. data_wb = DataWb.objects.filter(lot_no=lot_no).order_by('row_no')
  364. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no'))
  365. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no'))
  366. data_ho = list(chain(data_h1, data_h2))
  367. if first_result:
  368. out_limit = f"Out 外 ({first_result.MI18} - {first_result.MI19})"
  369. in_limit = f"In 内 ({first_result.MI22} - {first_result.MI23})"
  370. mid_limit = f"Middle 中 -"
  371. else:
  372. out_limit = f"Out 外"
  373. in_limit = f"In 内"
  374. mid_limit = f"Middle 中"
  375. # Prepare placeholders
  376. # placeholders = {}
  377. placeholders = clear_values(16,5)
  378. # for i in range(1,7):
  379. # for j in range(1,4):
  380. # placeholders[f'v{i}_{j}'] = 0
  381. placeholders['v6_0'] = placeholders['v14_0'] = out_limit
  382. placeholders['v7_0'] = placeholders['v15_0'] = mid_limit
  383. placeholders['v18_0'] = placeholders['v16_0'] = in_limit
  384. pprint(placeholders)
  385. pprint(manual_size_records)
  386. if first_result:
  387. w = first_result.PRO6
  388. placeholders['v4_1'] = placeholders['v12_1'] = w
  389. for m in manual_size_records:
  390. if m.size_name == "D":
  391. placeholders['v1_1'] = placeholders['v9_1'] = f'D{m.std} +{m.tolup} {m.tolun}'
  392. if m.size_name == "T":
  393. placeholders['v2_1'] = placeholders['v10_1'] = f'T{m.std} +{m.tolup} {m.tolun}'
  394. if m.size_name == "H":
  395. placeholders['v3_1'] = placeholders['v11_1'] = f'H{m.std} +{m.tolup} {m.tolun}'
  396. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  397. for r in data_ms_records:
  398. if r.row_no == 1:
  399. placeholders[f'v1_2'] = r.dsize
  400. placeholders[f'v1_3'] = r.dsizeok
  401. placeholders[f'v2_2'] = r.tsize
  402. placeholders[f'v2_3'] = r.tsizeok
  403. placeholders[f'v3_2'] = r.hsize
  404. placeholders[f'v3_3'] = r.hsizeok
  405. # if is_ok(r):
  406. # placeholders[f'v4_1'] = 'OK'
  407. # placeholders[f'v4_2'] = 'OK'
  408. # else:
  409. # placeholders[f'v4_1'] = 'NG'
  410. # placeholders[f'v4_2'] = 'OK'
  411. if r.row_no == 2:
  412. placeholders[f'v9_2'] = r.dsize
  413. placeholders[f'v9_3'] = r.dsizeok
  414. placeholders[f'v10_2'] = r.tsize
  415. placeholders[f'v10_3'] = r.tsizeok
  416. placeholders[f'v11_2'] = r.hsize
  417. placeholders[f'v11_3'] = r.hsizeok
  418. # if is_ok(r):
  419. # placeholders[f'v8_1'] = 'OK'
  420. # placeholders[f'v8_2'] = 'OK'
  421. # else:
  422. # placeholders[f'v8_1'] = 'NG'
  423. # placeholders[f'v8_2'] = 'NG'
  424. for r in data_wb:
  425. if r.row_no == 1:
  426. placeholders["v4_2"] = r.weight
  427. placeholders["v4_3"] = r.judgement
  428. if r.row_no == 2:
  429. placeholders["v12_2"] = r.weight
  430. placeholders["v12_3"] = r.judgement
  431. for r in data_ho:
  432. if r.row_no == 1:
  433. rmap = {'OUT': 6, 'MID': 7, 'IN': 8}
  434. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  435. idx = rmap.get(r.r_type, None)
  436. if idx:
  437. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  438. if r.row_no == 2:
  439. rmap = {'OUT': 14, 'MID': 15, 'IN': 16}
  440. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  441. idx = rmap.get(r.r_type, None)
  442. if idx:
  443. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  444. # hide_con(placeholders, "v5_1", "26:32")
  445. return placeholders
  446. def generate_dim_bal_app_rot_hard_values(lot_no, first_result):
  447. """
  448. Fetch dimension records from manualSize and DataMs models
  449. and generate placeholder values for Standard, Actual, and Judgement.
  450. Supports two row_no entries per lot.
  451. """
  452. # Fetch standard values from manualSize (limit to 2 rows)
  453. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  454. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  455. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  456. data_wb = DataWb.objects.filter(lot_no=lot_no).order_by('row_no')
  457. data_h1 = list(Data.objects.filter(lot_no=lot_no).order_by('row_no'))
  458. data_h2 = list(DataRl.objects.filter(lot_no=lot_no).order_by('row_no'))
  459. data_ho = list(chain(data_h1, data_h2))
  460. rotates = RotateData.objects.filter(lot_no=lot_no).order_by('row_no')
  461. if first_result:
  462. out_limit = f"Out 外 ({first_result.MI18} - {first_result.MI19})"
  463. in_limit = f"In 内 ({first_result.MI22} - {first_result.MI23})"
  464. mid_limit = f"Middle 中 -"
  465. else:
  466. out_limit = f"Out 外"
  467. in_limit = f"In 内"
  468. mid_limit = f"Middle 中"
  469. # Prepare placeholders
  470. # placeholders = {}
  471. placeholders = clear_values(18,5)
  472. # for i in range(1,7):
  473. # for j in range(1,4):
  474. # placeholders[f'v{i}_{j}'] = 0
  475. placeholders['v6_0'] = placeholders['v14_0'] = out_limit
  476. placeholders['v7_0'] = placeholders['v15_0'] = mid_limit
  477. placeholders['v18_0'] = placeholders['v16_0'] = in_limit
  478. pprint(placeholders)
  479. pprint(manual_size_records)
  480. if first_result:
  481. w = first_result.PRO6
  482. placeholders['v4_1'] = placeholders['v13_1'] = w
  483. for m in manual_size_records:
  484. if m.size_name == "D":
  485. placeholders['v1_1'] = placeholders['v10_1'] = f'D{m.std} +{m.tolup} {m.tolun}'
  486. if m.size_name == "T":
  487. placeholders['v2_1'] = placeholders['v11_1'] = f'T{m.std} +{m.tolup} {m.tolun}'
  488. if m.size_name == "H":
  489. placeholders['v3_1'] = placeholders['v12_1'] = f'H{m.std} +{m.tolup} {m.tolun}'
  490. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  491. for r in data_ms_records:
  492. if r.row_no == 1:
  493. placeholders[f'v1_2'] = r.dsize
  494. placeholders[f'v1_3'] = r.dsizeok
  495. placeholders[f'v2_2'] = r.tsize
  496. placeholders[f'v2_3'] = r.tsizeok
  497. placeholders[f'v3_2'] = r.hsize
  498. placeholders[f'v3_3'] = r.hsizeok
  499. # if is_ok(r):
  500. # placeholders[f'v4_1'] = 'OK'
  501. # placeholders[f'v4_2'] = 'OK'
  502. # else:
  503. # placeholders[f'v4_1'] = 'NG'
  504. # placeholders[f'v4_2'] = 'OK'
  505. if r.row_no == 2:
  506. placeholders[f'v10_2'] = r.dsize
  507. placeholders[f'v10_3'] = r.dsizeok
  508. placeholders[f'v11_2'] = r.tsize
  509. placeholders[f'v11_3'] = r.tsizeok
  510. placeholders[f'v12_2'] = r.hsize
  511. placeholders[f'v12_3'] = r.hsizeok
  512. # if is_ok(r):
  513. # placeholders[f'v8_1'] = 'OK'
  514. # placeholders[f'v8_2'] = 'OK'
  515. # else:
  516. # placeholders[f'v8_1'] = 'NG'
  517. # placeholders[f'v8_2'] = 'NG'
  518. for r in data_wb:
  519. if r.row_no == 1:
  520. placeholders["v4_2"] = r.weight
  521. placeholders["v4_3"] = r.judgement
  522. if r.row_no == 2:
  523. placeholders["v13_2"] = r.weight
  524. placeholders["v13_3"] = r.judgement
  525. for r in data_ho:
  526. if r.row_no == 1:
  527. rmap = {'OUT': 7, 'MID': 8, 'IN': 9}
  528. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  529. idx = rmap.get(r.r_type, None)
  530. if idx:
  531. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  532. if r.row_no == 2:
  533. rmap = {'OUT': 16, 'MID': 17, 'IN': 18}
  534. for index, v in enumerate(["p1", "p2", "p3", "avg", "rgrade"], start=1):
  535. idx = rmap.get(r.r_type, None)
  536. if idx:
  537. placeholders[f'v{idx}_{index}'] = getattr(r, v)
  538. for r in rotates:
  539. if r.row_no == 1:
  540. placeholders["v6_1"] = r.speed_spec
  541. placeholders["v6_2"] = r.speed_test
  542. placeholders["v6_3"] = r.speedok
  543. if r.row_no == 2:
  544. placeholders["v15_1"] = r.speed_spec
  545. placeholders["v15_2"] = r.speed_test
  546. placeholders["v15_3"] = r.speedok
  547. # hide_con(placeholders, "v5_1", "26:32")
  548. return placeholders
  549. def generate_centering_values(lot_no):
  550. """
  551. Fetch dimension records from manualSize and DataMs models
  552. and generate placeholder values for Standard, Actual, and Judgement.
  553. Supports two row_no entries per lot.
  554. """
  555. # Fetch standard values from manualSize (limit to 2 rows)
  556. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  557. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  558. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  559. # Prepare placeholders
  560. # placeholders = {}
  561. placeholders = clear_values(10,3)
  562. # for i in range(1,7):
  563. # for j in range(1,4):
  564. # placeholders[f'v{i}_{j}'] = 0
  565. pprint(placeholders)
  566. pprint(manual_size_records)
  567. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  568. for i,r in enumerate(data_ms_records, start=1):
  569. placeholders[f'v{i}_2'] = r.censize
  570. placeholders[f'v{i}_3'] = r.censizeok
  571. return placeholders
  572. def generate_t8_values(lot_no):
  573. """
  574. Fetch dimension records from manualSize and DataMs models
  575. and generate placeholder values for Standard, Actual, and Judgement.
  576. Supports two row_no entries per lot.
  577. """
  578. # Fetch standard values from manualSize (limit to 2 rows)
  579. placeholders = clear_values(8,10)
  580. manual_size_records = Manualsize.objects.filter(lotno=lot_no)
  581. # pprint(f"manual_size = {manual_size_records}")
  582. for m in manual_size_records:
  583. if m.size_name == "Thickness":
  584. for i in range(1,9):
  585. placeholders[f'v{i}_1'] = f'{m.std} +{m.tolup} {m.tolun}'
  586. # pprint("set std")
  587. # Fetch actual and judgement values from DataMs ordered by row_no (limit to 2 rows)
  588. data_ms_records = DataMs.objects.filter(lot_no=lot_no).order_by('row_no')
  589. # Prepare placeholders
  590. # placeholders = {}
  591. # for i in range(1,7):
  592. # for j in range(1,4):
  593. # placeholders[f'v{i}_{j}'] = 0
  594. # Ensure that we map each manualSize entry to a corresponding DataMs entry
  595. for i,r in enumerate(data_ms_records, start=1):
  596. placeholders[f'v{i}_2'] = r.tpoint1
  597. placeholders[f'v{i}_3'] = r.tpoint2
  598. placeholders[f'v{i}_4'] = r.tpoint3
  599. placeholders[f'v{i}_5'] = r.tpoint4
  600. placeholders[f'v{i}_10'] = r.tdiff
  601. return placeholders
  602. def merge_sheet_data_with_data(sheet_data, data):
  603. """
  604. Merge `sheet_data` with `data`.
  605. :param sheet_data: Dictionary containing the sheet-specific data.
  606. :param data: Dictionary containing general data.
  607. :return: A merged dictionary combining both `sheet_data` and `data`.
  608. """
  609. # Merge dictionaries using unpacking
  610. merged_data = {**data, **sheet_data}
  611. return merged_data
  612. def create_coi_file(lot_no, sheets, user, md):
  613. pprint("---- create_coi_file ---")
  614. pprint(md)
  615. qa1 = User.objects.get(pk=md['qa1'])
  616. qa2 = User.objects.get(pk=md['qa2'])
  617. accept = specialAccept = False
  618. if md['acceptStatus'] == "accepted":
  619. accept = True
  620. if md['acceptStatus'] == "special_accepted":
  621. specialAccept = True
  622. pprint(qa1)
  623. pprint(qa2)
  624. results = queryFromMaster(lot_no)
  625. first_result = results[0] if results else None
  626. sheet_data = {}
  627. for sheet_name in sheets:
  628. if sheet_name == 'hardness_out':
  629. sheet_data[sheet_name] = generate_hardness_out_values(lot_no)
  630. elif sheet_name == 'hardness_out_in':
  631. sheet_data[sheet_name] = generate_hardness_out_in_values(lot_no)
  632. elif sheet_name == 'hardness_both_size':
  633. sheet_data[sheet_name] = generate_hardness_both_size_values(lot_no, first_result)
  634. elif sheet_name == 'dimension':
  635. sheet_data[sheet_name] = generate_dimension_values(lot_no)
  636. elif sheet_name == 'dimension_app':
  637. sheet_data[sheet_name] = generate_dimension_app_values(lot_no)
  638. elif sheet_name == 'dimension_bal_weight':
  639. sheet_data[sheet_name] = generate_dimension_bal_weight_values(lot_no, first_result)
  640. elif sheet_name == 'centering':
  641. sheet_data[sheet_name] = generate_centering_values(lot_no)
  642. elif sheet_name == 'thickness_8_point':
  643. sheet_data[sheet_name] = generate_t8_values(lot_no)
  644. elif sheet_name == 'dim_bal_app_hard':
  645. sheet_data[sheet_name] = generate_dim_bal_app_hard_values(lot_no, first_result)
  646. elif sheet_name == 'dim_bal_app_rot_hard':
  647. sheet_data[sheet_name] = generate_dim_bal_app_rot_hard_values(lot_no, first_result)
  648. converted_data = convert_sheet_data(sheet_data)
  649. print(f"sheet_data \n {sheet_data}")
  650. print(f"converted_data \n {converted_data}")
  651. # results = queryFromMaster(lot_no)
  652. # first_result = results[0] if results else None
  653. try:
  654. pcs = int(first_result.PRO5) - int(first_result.PRO27)
  655. except:
  656. pcs = 0
  657. if first_result:
  658. size_str = f"{first_result.PRO10}x{first_result.PRO11}x{first_result.PRO12}";
  659. spec = f"{first_result.PRO13} {first_result.PRO14} {first_result.PRO15} {first_result.PRO16} {first_result.PRO17} {first_result.PRO18}"
  660. else:
  661. size_str = ""
  662. spec = ""
  663. data = {
  664. "code": first_result.PRO1 if first_result else "-",
  665. "customer": first_result.PRO1C if first_result else "-",
  666. "inspect_date": "2025-01-15",
  667. "lot_no": lot_no,
  668. "size": size_str,
  669. "lot_size": pcs,
  670. "spec": spec,
  671. # "hardness_out.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  672. # "hardness_out.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  673. "acc": accept, # Hide rows 24 to 28 if the prefix is "0"
  674. "spe_acc": specialAccept, # Hide rows 24 to 28 if the prefix is "0"
  675. # "hardness_out.qa1": f"{qa1.first_name} {qa1.last_name}",
  676. # "hardness_out.qa2": f"{qa2.first_name} {qa2.last_name}",
  677. "qa1": f"{qa1.first_name} {qa1.last_name}",
  678. "qa2": f"{qa2.first_name} {qa2.last_name}",
  679. "sign1": qa1.profile.signed_picture,
  680. "sign2": qa2.profile.signed_picture,
  681. "pos1": qa1.profile.get_position_display(),
  682. "pos2": qa2.profile.get_position_display()
  683. }
  684. merged_data = merge_sheet_data_with_data(converted_data, data)
  685. pprint(f"---- merged_data ---")
  686. pprint(merged_data)
  687. output_file = gen_xlsx(
  688. template_file=f"{settings.BASE_DIR}/report/coi_templates.xlsx",
  689. selected_sheets=sheets, # Replace with your actual sheet names
  690. prefix_filename=f"{settings.BASE_DIR}/media/coi_{lot_no}_",
  691. data=merged_data
  692. )
  693. report = Report.objects.create(
  694. name=lot_no,
  695. created_by=user,
  696. file=None # Leave this as None or assign a file if required
  697. )
  698. output_file_path = Path(output_file) # Convert to a Path object for convenience
  699. with open(output_file_path, "rb") as f:
  700. report.file.save(output_file_path.name, File(f), save=True)
  701. pprint(f"outputfile = {output_file}")
  702. return report
  703. SHEET_NAMES = {
  704. 'hardness_out': 'Hardness Out',
  705. 'hardness_out_in': 'Hardness Out/In',
  706. 'hardness_both_size': 'Hardness Both Size',
  707. 'dimension': 'Dimension',
  708. 'dimension_app': 'Dimension Appearance',
  709. 'dimension_bal_weight': 'Dimension Balance/Weight',
  710. 'dim_bal_app_hard': 'Dimension Balance/Appearance/Hardness',
  711. 'dim_bal_app_rot_hard': 'Dimension Balance/Appearance/Rotation/Hardness',
  712. 'thickness_8_point': 'Thickness 8 Points',
  713. 'centering': 'Centering',
  714. }
  715. def get_fields(model):
  716. # model_fields = {f.name: f for f in model._meta.get_fields()}
  717. # fields = list(model_fields.values())
  718. # return fields
  719. fields = [f for f in model._meta.get_fields() if not f.auto_created]
  720. return fields
  721. def filter_by_lot_no(lot_no):
  722. models = [Data, DataMs, DataRl, DataWb, LotSummary, LotSummaryRl, LotSummaryWb, PressCal, RotateData ] # List of models to process
  723. results = {}
  724. fields = {}
  725. for model in models:
  726. model_fields = [f.name for f in model._meta.get_fields()]
  727. # Check if "id" and "row_no" are in the model's fields
  728. order_fields = []
  729. if "id" in model_fields:
  730. order_fields.append("id")
  731. if "row_no" in model_fields:
  732. order_fields.append("row_no")
  733. # Dynamically filter and order results
  734. model_name = model.__name__
  735. if order_fields:
  736. results[model_name] = model.objects.filter(lot_no=lot_no).order_by(*order_fields)
  737. else:
  738. results[model_name] = model.objects.filter(lot_no=lot_no) # No
  739. fields[model_name] = get_fields(model)
  740. return results, fields
  741. def coi_view(request):
  742. pprint(f"xxxx method = xxx {request.method}")
  743. users = User.objects.all()
  744. if request.method == "POST":
  745. pprint(request.POST)
  746. exports = request.POST.getlist("exports") # Retrieve the list of selected values
  747. pprint(f"Selected Export Options: {exports}")
  748. if 'export' in request.POST:
  749. data = {
  750. "customer": "Tum Coder",
  751. "inspect_date": "2025-01-15",
  752. "lot_no": "12345",
  753. "staff_name": "Tum 8888",
  754. "man_name": "Tum 999",
  755. "size": "Large",
  756. "lot_size": "10 pcs",
  757. "spec": "Spec-A",
  758. "hardness_out.d1_act": "10",
  759. "hardness_out.d2_act": "0[24:28]", # Hide rows 24 to 28 if the prefix is "0"
  760. "hardness_out.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  761. "hardness_out.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  762. "dimension_app.d1_act": "33",
  763. "dimension_app.d2_act": "0[26:32]", # Hide rows 24 to 28 if the prefix is "0"
  764. "dimension_app.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  765. "dimension_app.spe_acc": True, # Hide rows 24 to 28 if the prefix is "0"
  766. }
  767. output_file = gen_xlsx(
  768. template_file="/app/report/coi_templates.xlsx",
  769. selected_sheets=exports, # Replace with your actual sheet names
  770. prefix_filename="/app/media/coi",
  771. data=data
  772. )
  773. report = Report.objects.create(
  774. name=request.POST.get('lot_no','Untitled'),
  775. created_by=request.user,
  776. file=None # Leave this as None or assign a file if required
  777. )
  778. output_file_path = Path(output_file) # Convert to a Path object for convenience
  779. with open(output_file_path, "rb") as f:
  780. report.file.save(output_file_path.name, File(f), save=True)
  781. pprint(f"outputfile = {output_file}")
  782. if 'search_lot' in request.POST:
  783. lot_no = request.POST.get('lot_no', None)
  784. lot_no = lot_no.strip()
  785. if lot_no:
  786. results = queryFromMaster(lot_no)
  787. first_result = results[0] if results else None
  788. try:
  789. pcs = int(first_result.PRO5) - int(first_result.PRO27)
  790. except:
  791. pcs = 0
  792. if first_result:
  793. size_str = f"{first_result.PRO10}x{first_result.PRO11}x{first_result.PRO12}";
  794. spec = f"{first_result.PRO13} {first_result.PRO14} {first_result.PRO15} {first_result.PRO16} {first_result.PRO17} {first_result.PRO18}"
  795. else:
  796. size_str = ""
  797. spec = ""
  798. results, fields = filter_by_lot_no(lot_no)
  799. # results1 = Data.objects.filter(lot_no=lot_no).order_by("id", "row_no")
  800. # fields1 = get_fields(Data)
  801. # results2 = DataMs.objects.filter(lot_no=lot_no).order_by("id", "row_no")
  802. # fields2 = get_fields(DataMs)
  803. return render(request, 'report/coi.html', {'result': first_result,
  804. 'pcs':pcs,
  805. 'size_str': size_str,
  806. 'lot_no': lot_no,
  807. 'spec': spec, 'users': users, 'SHEET_NAMES': SHEET_NAMES,
  808. 'results': results, 'fields': fields})
  809. messages.success(request, "Request Sent")
  810. return redirect(request.path_info)
  811. return render(request, 'report/coi.html', {'SHEET_NAMES': SHEET_NAMES, 'users': users})
  812. @csrf_exempt # Disable CSRF for API requests (ensure this is secure in production)
  813. @login_required
  814. def gen_report_view(request):
  815. if request.method == "POST":
  816. # try:
  817. # Parse JSON data from the request body
  818. data = json.loads(request.body)
  819. lot_no = data.get("lot_no").strip()
  820. exports = data.get("exports")
  821. qa1 = data.get('qa1')
  822. qa2 = data.get('qa2')
  823. print(f"data = {data}")
  824. if not lot_no:
  825. return HttpResponseBadRequest("Missing 'lot_no' in request data")
  826. # Call the `create_coi_file` function with the provided lot_no
  827. report = create_coi_file(lot_no, exports, request.user, {'qa1': qa1, 'qa2': qa2, \
  828. 'acceptStatus': data.get('acceptStatus')})
  829. # Return a success response with the report details
  830. return JsonResponse({
  831. "message": "Report generated successfully",
  832. "report_id": report.id,
  833. "file_url": report.file.url if report.file else None,
  834. })
  835. # except json.JSONDecodeError:
  836. # return HttpResponseBadRequest("Invalid JSON data")
  837. # except Exception as e:
  838. # pprint(e)
  839. # return JsonResponse({"error": str(e)}, status=500)
  840. else:
  841. return HttpResponseBadRequest("Only POST requests are allowed")