Нема описа

views.py 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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. from .gen_report import gen_xlsx
  12. from django.core.files.base import File
  13. from pathlib import Path
  14. from django.views.decorators.csrf import csrf_exempt
  15. from django.http import JsonResponse, HttpResponseBadRequest
  16. import json
  17. from django.contrib.auth.decorators import login_required
  18. from django.contrib.auth.models import User
  19. from legacy.models import Data
  20. from django.conf import settings
  21. def index(request):
  22. reports = Report.objects.all()
  23. report_filter = ReportFilter(request.GET, queryset=reports)
  24. # Paginate the filtered queryset
  25. paginator = Paginator(report_filter.qs, 10) # Show 10 reports per page
  26. page_number = request.GET.get('page')
  27. page_obj = paginator.get_page(page_number)
  28. context = {
  29. 'filter': report_filter,
  30. 'page_obj': page_obj,
  31. }
  32. return render(request, 'report/index.html', context)
  33. def report_create_view(request):
  34. if request.method == "POST":
  35. form = ReportForm(request.POST)
  36. if form.is_valid():
  37. form.save()
  38. messages.success(request, "Report created successfully!")
  39. return redirect("report:report_index") # Adjust with your report list view name
  40. else:
  41. form = ReportForm()
  42. return render(request, "report/create.html", {"form": form})
  43. class ReportCRUDView(ConfigurableCRUDView):
  44. model = Report
  45. list_template_name = 'legacy/datacrud_list.html'
  46. detail_template_name = 'legacy/datacrud_detail.html'
  47. form_template_name = 'report/report_form.html'
  48. confirm_delete_template_name = 'legacy/datacrud_confirm_delete.html'
  49. filterset_class = ReportFilter
  50. page_title = "Reports"
  51. # URL name mappings
  52. list_url_name = 'report:report-list'
  53. create_url_name = 'report:report-create'
  54. update_url_name = 'report:report-update'
  55. delete_url_name = 'report:report-delete'
  56. config_fields = ["name", "file", "created_by", "created_at"]
  57. config_field_orders = ["id", "name", "created_by"]
  58. # config_readonly_fields = ["lot_no"]
  59. # config_edit_fields = ["lot_no", "code"]
  60. ordering = ["-created_at", "-id",]
  61. def convert_sheet_data(sheet_data):
  62. """
  63. Convert sheet_data to the required form with prefixed keys.
  64. :param sheet_data: Dictionary with sheet names as keys and their data as values.
  65. :return: Dictionary in the required key-value format.
  66. """
  67. converted_data = {}
  68. for sheet_name, data in sheet_data.items():
  69. for key, value in data.items():
  70. # Prefix each key with the sheet name
  71. converted_key = f"{sheet_name}.{key}"
  72. converted_data[converted_key] = value
  73. return converted_data
  74. def hide_con(placeholders, mark_value, hide_rows):
  75. """
  76. Updates the 'placeholders' dictionary with a mark value and hide rows range.
  77. :param placeholders: The dictionary to update.
  78. :param mark_value: The key to check or update in the placeholders.
  79. :param hide_rows: The row range to append in the format '[start:end]'.
  80. """
  81. if mark_value in placeholders:
  82. placeholders[mark_value] = f"{placeholders[mark_value]}[{hide_rows}]"
  83. else:
  84. placeholders[mark_value] = f"0[{hide_rows}]"
  85. def generate_hardness_out_values(lot_no):
  86. """
  87. Generate a dictionary of placeholder values for a given lot_no.
  88. :param lot_no: The lot number to query data for.
  89. :return: A dictionary with placeholders (e.g., v1_1, v1_2, ...) as keys and their respective values.
  90. """
  91. # Query the Data model for records matching the given lot_no
  92. records = Data.objects.filter(lot_no=lot_no).order_by('row_no')
  93. print(f"records {lot_no} = {records.values()}")
  94. # Initialize an empty dictionary to store placeholder values
  95. placeholders = {}
  96. # Iterate over the records to populate placeholder values
  97. for record_idx, record in enumerate(records, start=1):
  98. placeholders[f'v{record_idx}_1'] = record.p1 # Checkpoint 1 value
  99. placeholders[f'v{record_idx}_2'] = record.p2 # Checkpoint 2 value
  100. placeholders[f'v{record_idx}_3'] = record.p3 # Checkpoint 3 value
  101. placeholders[f'v{record_idx}_4'] = record.avg # Average value
  102. placeholders[f'v{record_idx}_5'] = record.rgrade # Judgment value
  103. return placeholders
  104. def generate_hardness_out_in_values(lot_no):
  105. # Fetch records from the Data model
  106. records = Data.objects.filter(lot_no=lot_no).order_by('row_no')
  107. out_data = []
  108. in_data = []
  109. # Separate OUT and IN data
  110. for record in records:
  111. if record.r_type.upper() in ["OUT", "TOP", "FA1", "UPP", "UPPE", "RIM"]:
  112. out_data.append(record)
  113. elif record.r_type.upper() in ["IN", "UNDER", "UND", "FA2", "LOW", "LOWE", "BASE", "SOKO", "IN*"]:
  114. in_data.append(record)
  115. # Prepare placeholders
  116. placeholders = {}
  117. for idx, record in enumerate(out_data, start=1):
  118. placeholders[f'v{idx}_1'] = record.p1
  119. placeholders[f'v{idx}_2'] = record.p2
  120. placeholders[f'v{idx}_3'] = record.p3
  121. placeholders[f'v{idx}_4'] = record.avg
  122. placeholders[f'v{idx}_5'] = record.rgrade
  123. for idx, record in enumerate(in_data, start=1):
  124. placeholders[f'v{len(out_data) + idx}_1'] = record.p1
  125. placeholders[f'v{len(out_data) + idx}_2'] = record.p2
  126. placeholders[f'v{len(out_data) + idx}_3'] = record.p3
  127. placeholders[f'v{len(out_data) + idx}_4'] = record.avg
  128. placeholders[f'v{len(out_data) + idx}_5'] = record.rgrade
  129. # if "v3_1" in placeholders:
  130. # placeholders["v3_1"] = f"{placeholders['v3_1']}[25:28]"
  131. # else:
  132. # placeholders[f"v3_1"] = "0[25:28]"
  133. hide_con(placeholders, "v3_1", "25:28")
  134. return placeholders
  135. def merge_sheet_data_with_data(sheet_data, data):
  136. """
  137. Merge `sheet_data` with `data`.
  138. :param sheet_data: Dictionary containing the sheet-specific data.
  139. :param data: Dictionary containing general data.
  140. :return: A merged dictionary combining both `sheet_data` and `data`.
  141. """
  142. # Merge dictionaries using unpacking
  143. merged_data = {**data, **sheet_data}
  144. return merged_data
  145. def create_coi_file(lot_no, sheets, user, md):
  146. pprint("---- create_coi_file ---")
  147. pprint(md)
  148. qa1 = User.objects.get(pk=md['qa1'])
  149. qa2 = User.objects.get(pk=md['qa2'])
  150. pprint(qa1)
  151. pprint(qa2)
  152. sheet_data = {}
  153. for sheet_name in sheets:
  154. match sheet_name:
  155. case 'hardness_out':
  156. sheet_data[sheet_name] = generate_hardness_out_values(lot_no)
  157. case 'hardness_out_in':
  158. sheet_data[sheet_name] = generate_hardness_out_in_values(lot_no)
  159. converted_data = convert_sheet_data(sheet_data)
  160. print(f"sheet_data \n {sheet_data}")
  161. print(f"converted_data \n {converted_data}")
  162. data = {
  163. "customer": "Tum Coder",
  164. "inspect_date": "2025-01-15",
  165. "lot_no": "12345",
  166. "staff_name": "Tum 8888",
  167. "man_name": "Tum 999",
  168. "size": "Large",
  169. "pcs": "10 pcs",
  170. "spec": "Spec-A",
  171. "hardness_out.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  172. "hardness_out.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  173. "acc": True, # Hide rows 24 to 28 if the prefix is "0"
  174. "spe_acc": True, # Hide rows 24 to 28 if the prefix is "0"
  175. # "hardness_out.qa1": f"{qa1.first_name} {qa1.last_name}",
  176. # "hardness_out.qa2": f"{qa2.first_name} {qa2.last_name}",
  177. "qa1": f"{qa1.first_name} {qa1.last_name}",
  178. "qa2": f"{qa2.first_name} {qa2.last_name}",
  179. "sign1": qa1.profile.signed_picture,
  180. "sign2": qa2.profile.signed_picture,
  181. "pos1": qa1.profile.get_position_display(),
  182. "pos2": qa2.profile.get_position_display()
  183. }
  184. merged_data = merge_sheet_data_with_data(converted_data, data)
  185. pprint(f"---- merged_data ---")
  186. pprint(merged_data)
  187. output_file = gen_xlsx(
  188. template_file=f"{settings.BASE_DIR}/report/coi_templates.xlsx",
  189. selected_sheets=sheets, # Replace with your actual sheet names
  190. prefix_filename=f"{settings.BASE_DIR}/media/coi",
  191. data=merged_data
  192. )
  193. report = Report.objects.create(
  194. name=lot_no,
  195. created_by=user,
  196. file=None # Leave this as None or assign a file if required
  197. )
  198. output_file_path = Path(output_file) # Convert to a Path object for convenience
  199. with open(output_file_path, "rb") as f:
  200. report.file.save(output_file_path.name, File(f), save=True)
  201. pprint(f"outputfile = {output_file}")
  202. return report
  203. SHEET_NAMES = {
  204. 'hardness_out': 'Hardness Out',
  205. 'hardness_out_in': 'Hardness Out/In',
  206. 'hardness_both_size': 'Hardness Both Size',
  207. 'dimension': 'Dimension',
  208. 'dimension_app': 'Dimension Appearance',
  209. 'dimension_bal_weight': 'Dimension Balance/Weight',
  210. 'dim_bal_app_hard': 'Dimension Balance/Appearance/Hardness',
  211. 'dim_bal_app_rot_hard': 'Dimension Balance/Appearance/Rotation/Hardness',
  212. 'thickness_8_point': 'Thickness 8 Points',
  213. 'centering': 'Centering',
  214. }
  215. def get_fields(model):
  216. # model_fields = {f.name: f for f in model._meta.get_fields()}
  217. # fields = list(model_fields.values())
  218. # return fields
  219. fields = [f for f in model._meta.get_fields() if not f.auto_created]
  220. return fields
  221. def filter_by_lot_no(lot_no):
  222. models = [Data, DataMs, DataRl, DataWb, LotSummary, LotSummaryRl, LotSummaryWb, PressCal, RotateData ] # List of models to process
  223. results = {}
  224. fields = {}
  225. for model in models:
  226. model_fields = [f.name for f in model._meta.get_fields()]
  227. # Check if "id" and "row_no" are in the model's fields
  228. order_fields = []
  229. if "id" in model_fields:
  230. order_fields.append("id")
  231. if "row_no" in model_fields:
  232. order_fields.append("row_no")
  233. # Dynamically filter and order results
  234. model_name = model.__name__
  235. if order_fields:
  236. results[model_name] = model.objects.filter(lot_no=lot_no).order_by(*order_fields)
  237. else:
  238. results[model_name] = model.objects.filter(lot_no=lot_no) # No
  239. fields[model_name] = get_fields(model)
  240. return results, fields
  241. def coi_view(request):
  242. pprint(f"xxxx method = xxx {request.method}")
  243. users = User.objects.all()
  244. if request.method == "POST":
  245. pprint(request.POST)
  246. exports = request.POST.getlist("exports") # Retrieve the list of selected values
  247. pprint(f"Selected Export Options: {exports}")
  248. if 'export' in request.POST:
  249. data = {
  250. "customer": "Tum Coder",
  251. "inspect_date": "2025-01-15",
  252. "lot_no": "12345",
  253. "staff_name": "Tum 8888",
  254. "man_name": "Tum 999",
  255. "size": "Large",
  256. "lot_size": "10 pcs",
  257. "spec": "Spec-A",
  258. "hardness_out.d1_act": "10",
  259. "hardness_out.d2_act": "0[24:28]", # Hide rows 24 to 28 if the prefix is "0"
  260. "hardness_out.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  261. "hardness_out.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
  262. "dimension_app.d1_act": "33",
  263. "dimension_app.d2_act": "0[26:32]", # Hide rows 24 to 28 if the prefix is "0"
  264. "dimension_app.acc": True, # Hide rows 24 to 28 if the prefix is "0"
  265. "dimension_app.spe_acc": True, # Hide rows 24 to 28 if the prefix is "0"
  266. }
  267. output_file = gen_xlsx(
  268. template_file="/app/report/coi_templates.xlsx",
  269. selected_sheets=exports, # Replace with your actual sheet names
  270. prefix_filename="/app/media/coi",
  271. data=data
  272. )
  273. report = Report.objects.create(
  274. name=request.POST.get('lot_no','Untitled'),
  275. created_by=request.user,
  276. file=None # Leave this as None or assign a file if required
  277. )
  278. output_file_path = Path(output_file) # Convert to a Path object for convenience
  279. with open(output_file_path, "rb") as f:
  280. report.file.save(output_file_path.name, File(f), save=True)
  281. pprint(f"outputfile = {output_file}")
  282. if 'search_lot' in request.POST:
  283. lot_no = request.POST.get('lot_no', None)
  284. lot_no = lot_no.strip()
  285. if lot_no:
  286. results = queryFromMaster(lot_no)
  287. first_result = results[0] if results else None
  288. try:
  289. pcs = int(first_result.PRO5) - int(first_result.PRO27)
  290. except:
  291. pcs = 0
  292. if first_result:
  293. size_str = f"{first_result.PRO10}x{first_result.PRO11}x{first_result.PRO12}";
  294. spec = f"{first_result.PRO13} {first_result.PRO14} {first_result.PRO15} {first_result.PRO16} {first_result.PRO17} {first_result.PRO18}"
  295. else:
  296. size_str = ""
  297. spec = ""
  298. results, fields = filter_by_lot_no(lot_no)
  299. # results1 = Data.objects.filter(lot_no=lot_no).order_by("id", "row_no")
  300. # fields1 = get_fields(Data)
  301. # results2 = DataMs.objects.filter(lot_no=lot_no).order_by("id", "row_no")
  302. # fields2 = get_fields(DataMs)
  303. return render(request, 'report/coi.html', {'result': first_result,
  304. 'pcs':pcs,
  305. 'size_str': size_str,
  306. 'lot_no': lot_no,
  307. 'spec': spec, 'users': users, 'SHEET_NAMES': SHEET_NAMES,
  308. 'results': results, 'fields': fields})
  309. messages.success(request, "Request Sent")
  310. return redirect(request.path_info)
  311. return render(request, 'report/coi.html', {'SHEET_NAMES': SHEET_NAMES, 'users': users})
  312. @csrf_exempt # Disable CSRF for API requests (ensure this is secure in production)
  313. @login_required
  314. def gen_report_view(request):
  315. if request.method == "POST":
  316. # try:
  317. # Parse JSON data from the request body
  318. data = json.loads(request.body)
  319. lot_no = data.get("lot_no").strip()
  320. exports = data.get("exports")
  321. qa1 = data.get('qa1')
  322. qa2 = data.get('qa2')
  323. print(f"data = {data}")
  324. if not lot_no:
  325. return HttpResponseBadRequest("Missing 'lot_no' in request data")
  326. # Call the `create_coi_file` function with the provided lot_no
  327. report = create_coi_file(lot_no, exports, request.user, {'qa1': qa1, 'qa2': qa2})
  328. # Return a success response with the report details
  329. return JsonResponse({
  330. "message": "Report generated successfully",
  331. "report_id": report.id,
  332. "file_url": report.file.url if report.file else None,
  333. })
  334. # except json.JSONDecodeError:
  335. # return HttpResponseBadRequest("Invalid JSON data")
  336. # except Exception as e:
  337. # pprint(e)
  338. # return JsonResponse({"error": str(e)}, status=500)
  339. else:
  340. return HttpResponseBadRequest("Only POST requests are allowed")