import os from docx import Document from rest_framework import status from rest_framework.decorators import api_view from rest_framework.response import Response from app.models import * from datetime import datetime from num2words import num2words from docx.shared import Inches, Pt from docx.enum.text import WD_ALIGN_PARAGRAPH import numpy as np import mammoth import subprocess #============================================================================= BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) static_folder = os.path.join(BASE_DIR, "static") #============================================================================= def replace_text(doc, old_text, new_text): for para in doc.paragraphs: for run in para.runs: if old_text in run.text: run.text = run.text.replace(old_text, new_text) for section in doc.sections: footer = section.footer for paragraph in footer.paragraphs: for run in paragraph.runs: # Bỏ qua field PAGE (thường có style đặc biệt hoặc chứa "PAGE" trong XML) if "PAGE" in run._element.xml: continue if old_text in run.text: run.text = run.text.replace(old_text, new_text) #============================================================================= def base_replace(doc, date): replace_text(doc, "[day]", str(date.day)) replace_text(doc, "[month]", str(date.month)) replace_text(doc, "[year]", str(date.year)) replace_text(doc, "[start_date]", date.strftime("%d/%m/%Y")) #============================================================================= def convert_docx_to_html(docx_path, html_path): with open(docx_path, "rb") as docx_file: result = mammoth.convert_to_html(docx_file) html = result.value # HTML string with open(html_path, "w", encoding="utf-8") as html_file: # Thêm thẻ vào đầu html_with_encoding = f""" {html} """ html_file.write(html_with_encoding) #============================================================================= def docx_to_pdf(input_path, output_dir=None): if output_dir is None: output_dir = os.path.dirname(os.path.abspath(input_path)) subprocess.run([ "libreoffice", "--headless", # chạy không mở GUI "--convert-to", "pdf", "--outdir", output_dir, input_path ], check=True) #============================================================================= def insert_image_after_keyword(doc, keywords, image_path, full_name, time): try: for table in doc.tables: for row in table.rows: for cell in row.cells: for para in cell.paragraphs: for keyword in keywords: if keyword in para.text: print('==TEXT FOUNDED==', keyword, image_path, full_name) p = cell.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(2) p.add_run().add_picture(image_path, width=Inches(2)) p = cell.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(2) run = p.add_run(full_name) run.bold = True p = cell.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(2) p.add_run(time) break; except Exception as e: print("==INSERT IMAGE ERROR==", e) #============================================================================= @api_view(['GET']) def create_contract(request): code = request.query_params['code'] if request.query_params.get('code') != None else None if code == None: return Response(status = status.HTTP_400_BAD_REQUEST) # mapping columns = ['code', 'fullname', 'phone', 'create_time', 'customer__dob', 'legal_code', 'issue_date', 'issue_place', 'product__type__code', 'address', 'approve_amount', 'approve_term', 'address', 'loanapp__code', 'loanapp__rate_info', 'customer', 'loanapp__valid_from', 'loanapp__valid_to', 'product__category__code', 'loanapp__beneficiary_account', 'loanapp__beneficiary_bank'] # application application = Application.objects.filter(code=code).values(*columns).first() if application == None: return Response(status = status.HTTP_400_BAD_REQUEST) # contract contract = Contract.objects.filter(application__code=code).first() cust_people = Customer_People.objects.filter(customer=application['customer']) singed = contract.signature if contract!= None else None keywords = ["Sign, full name)"] # application is unsecured # if application['product__type__code'] == 'unsecured': # keywords = ["(Ký, ghi rõ họ tên)", "(Sign, full name)"] # # contract # docx_path = static_folder + '/contract/contract_unsecured.docx' # output_path = static_folder + "/contract/{}_contract.docx".format(code) # #html_contract = static_folder + "/contract/{}_contract.html".format(code) # doc = Document(docx_path) # base_replace(doc, application['loanapp__valid_from']) # # confirmation # docx_confirm = static_folder + '/contract/confirmation_unsecured.docx' # output_confirm = static_folder + "/contract/{}_confirmation.docx".format(code) # #html_confirm = static_folder + "/contract/{}_confirmation.html".format(code) # doc_confirm = Document(docx_confirm) # base_replace(doc_confirm, application['loanapp__valid_from']) # # replace # for text in columns: # value = application[text] # if text.find('date') >=0 or text.find('dob')>=0 or text.find('__valid')>=0: # value = value.strftime("%d/%m/%Y") # elif text.find('amount')>=0: # value = "{:,}".format(value).replace(",", ".") # elif text == 'create_time': # value = application['loanapp__valid_from'].strftime("%d/%m/%Y") # elif text == 'approve_term': # value = str(int(round(((application['loanapp__valid_to'] - application['loanapp__valid_from']).days) / 30, 0))) # # replace # replace_text(doc, "[{}]".format(text), str(value)) # replace_text(doc_confirm, "[{}]".format(text), str(value)) # # output # replace_text(doc, '[inword]', num2words(application['approve_amount'], lang='vi')) # replace_text(doc_confirm, '[inword]', num2words(application['approve_amount'], lang='vi')) # # insert image # if singed: # file_name = static_folder + '/files/' + contract.signature.file # print("Signed", file_name) # insert_image_after_keyword(doc, keywords, file_name, application['fullname'], contract.update_time.strftime("%d/%m/%Y")) # insert_image_after_keyword(doc_confirm, keywords, file_name, application['fullname'], contract.update_time.strftime("%d/%m/%Y")) # doc.save(output_path) # doc_confirm.save(output_confirm) # # convert-to-pdf # docx_to_pdf(output_path) # docx_to_pdf(output_confirm) # #convert_docx_to_html(output_path, html_contract) # # arr = [{"code": 'contract', "name": 'Hợp đồng', "en": "Contract", "file": "{}_contract.docx".format(code), # # "html": "{}_contract.html".format(code), "pdf": "{}_contract.pdf".format(code)}] # arr = [{"code": 'contract', "name": 'Hợp đồng', "en": "Contract", "file": "{}_contract.docx".format(code), "pdf": "{}_contract.pdf".format(code)}, # {"code": 'confirmation', "name": 'Xác nhận', "en": "Confirmation", "file": "{}_confirmation.docx".format(code), "pdf": "{}_confirmation.pdf".format(code)}] # else: if True: # contract docx_path = static_folder + '/contract/contract.docx' output_path = static_folder + "/contract/{}_contract.docx".format(code) #html_contract = static_folder + "/contract/{}_contract.html".format(code) doc = Document(docx_path) base_replace(doc, application['loanapp__valid_from']) # agreement docx_agree = static_folder + '/contract/agreement.docx' if application['product__category__code'] == 'phone' or application['product__category__code'] == 'laptop': docx_agree = static_folder + '/contract/agreement_phone.docx' output_agree = static_folder + "/contract/{}_agreement.docx".format(code) #html_agree = static_folder + "/contract/{}_agreement.html".format(code) doc_agree = Document(docx_agree) base_replace(doc_agree, application['loanapp__valid_from']) # commitment docx_commit = static_folder + '/contract/commitment.docx' output_commit = static_folder + "/contract/{}_commitment.docx".format(code) #html_commit = static_folder + "/contract/{}_commitment.html".format(code) doc_commit = Document(docx_commit) base_replace(doc_commit, application['loanapp__valid_from']) # pawn docx_pawn = static_folder + '/contract/pawn.docx' output_pawn = static_folder + "/contract/{}_pawn.docx".format(code) #html_pawn = static_folder + "/contract/{}_pawn.html".format(code) doc_pawn = Document(docx_pawn) base_replace(doc_pawn, application['loanapp__valid_from']) # confirmation docx_confirm = static_folder + '/contract/confirmation.docx' output_confirm = static_folder + "/contract/{}_confirmation.docx".format(code) #html_confirm = static_folder + "/contract/{}_confirmation.html".format(code) doc_confirm = Document(docx_confirm) base_replace(doc_confirm, application['loanapp__valid_from']) # replace for text in columns: value = application[text] if text.find('date') >=0 or text.find('dob')>=0 or text.find('__valid')>=0: value = value.strftime("%d/%m/%Y") elif text.find('amount')>=0: value = "{:,}".format(value).replace(",", ".") elif text == 'create_time': value = application['loanapp__valid_from'].strftime("%d/%m/%Y") elif text == 'approve_term': value = str(int(round(((application['loanapp__valid_to'] - application['loanapp__valid_from']).days) / 30, 0))) # replace value = ' ' if value == None else value replace_text(doc, "[{}]".format(text), str(value)) replace_text(doc_agree, "[{}]".format(text), str(value)) replace_text(doc_commit, "[{}]".format(text), str(value)) replace_text(doc_pawn, "[{}]".format(text), str(value)) replace_text(doc_confirm, "[{}]".format(text), str(value)) #end_date replace_text(doc, '[inword]', num2words(application['approve_amount'], lang='vi')) replace_text(doc_confirm, '[inword]', num2words(application['approve_amount'], lang='vi')) replace_text(doc_pawn, '[inword]', num2words(application['approve_amount'], lang='vi')) replace_text(doc_pawn, '[inword_en]', num2words(application['approve_amount'], lang='en')) if application['loanapp__beneficiary_account']: replace_text(doc_confirm, '[tickoffice]', "☐") replace_text(doc_confirm, '[tickbank]', "✓") else: replace_text(doc_confirm, '[tickoffice]', "✓") replace_text(doc_confirm, '[tickbank]', "☐") # collateral mapping = ['collateral__seri_number', 'collateral__code', 'collateral__appraisal_value', 'collateral__type__name', 'collateral__detail', 'collateral__status__name', 'collateral__vehicle_number', 'collateral__engine_number', 'collateral__year_mfg'] collateral = Loan_Collateral.objects.filter(loan__code=application['loanapp__code']).values(*mapping).first() if collateral: for text in mapping: value = collateral[text] if text.find('value')>=0: value = "{:,}".format(np.int64(value)).replace(",", ".") value = '' if value==None else value replace_text(doc, "[{}]".format(text), str(value)) replace_text(doc_agree, "[{}]".format(text), str(value)) replace_text(doc_commit, "[{}]".format(text), str(value)) replace_text(doc_pawn, "[{}]".format(text), str(value)) replace_text(doc_confirm, "[{}]".format(text), str(value)) else: for text in mapping: value = ' ' replace_text(doc, "[{}]".format(text), str(value)) replace_text(doc_agree, "[{}]".format(text), str(value)) replace_text(doc_commit, "[{}]".format(text), str(value)) replace_text(doc_pawn, "[{}]".format(text), str(value)) replace_text(doc_confirm, "[{}]".format(text), str(value)) # relation for i in [1,2,3,4]: text1 = '[fullname{}]'.format(i) text2 = '[phone{}]'.format(i) text3 = '[relation{}]'.format(i) people_info = cust_people[i-1] if i <= cust_people.count() else None if people_info: replace_text(doc_pawn, text1, people_info.people.fullname) replace_text(doc_pawn, text2, people_info.people.phone) replace_text(doc_pawn, text3, people_info.relation.name) else: replace_text(doc_pawn, text1, ' ') replace_text(doc_pawn, text2, ' ') replace_text(doc_pawn, text3, ' ') # insert image if singed: file_name = static_folder + '/files/' + contract.signature.file print("Signed", file_name) insert_image_after_keyword(doc, keywords, file_name, application['fullname'], contract.update_time.strftime("%d/%m/%Y")) insert_image_after_keyword(doc_agree, keywords, file_name, application['fullname'], contract.update_time.strftime("%d/%m/%Y")) insert_image_after_keyword(doc_commit, keywords, file_name, application['fullname'], contract.update_time.strftime("%d/%m/%Y")) insert_image_after_keyword(doc_pawn, keywords, file_name, application['fullname'], contract.update_time.strftime("%d/%m/%Y")) insert_image_after_keyword(doc_confirm, keywords, file_name, application['fullname'], contract.update_time.strftime("%d/%m/%Y")) # output doc.save(output_path) doc_agree.save(output_agree) doc_commit.save(output_commit) doc_pawn.save(output_pawn) doc_confirm.save(output_confirm) # convert_docx_to_html(output_path, html_contract) # convert_docx_to_html(output_agree, html_agree) # convert_docx_to_html(output_commit, html_commit) # convert_docx_to_html(output_pawn, html_pawn) # convert_docx_to_html(output_confirm, html_confirm) docx_to_pdf(output_path) docx_to_pdf(output_agree) docx_to_pdf(output_commit) docx_to_pdf(output_pawn) docx_to_pdf(output_confirm) # arr = [{"code": 'contract', "name": 'Hợp đồng', "en": "Contract", "file": "{}_contract.docx".format(code), "html": "{}_contract.html".format(code), "pdf": "{}_contract.pdf".format(code)}, # {"code": 'agreement', "name": 'Thỏa thuận', "en": "Agreement", "file": "{}_agreement.docx".format(code), "html": "{}_agreement.html".format(code), "pdf": "{}_agreement.pdf".format(code)}, # {"code": 'commitment', "name": 'Cam kết', "en": "Commitment", "file": "{}_commitment.docx".format(code), "html": "{}_commitment.html".format(code), "pdf": "{}_commitment.pdf".format(code)}, # {"code": 'pawn', "name": 'Cầm cố', "en": "Pawn", "file": "{}_pawn.docx".format(code), "html": "{}_pawn.html".format(code), "pdf": "{}_pawn.pdf".format(code)}, # {"code": 'confirmation', "name": 'Xác nhận', "en": "Confirmation", "file": "{}_confirmation.docx".format(code), "html": "{}_confirmation.html".format(code), "pdf": "{}_confirmation.pdf".format(code)}] arr = [{"code": 'contract', "name": 'Hợp đồng', "en": "Contract", "file": "{}_contract.docx".format(code), "pdf": "{}_contract.pdf".format(code)}, {"code": 'agreement', "name": 'Thỏa thuận', "en": "Agreement", "file": "{}_agreement.docx".format(code), "pdf": "{}_agreement.pdf".format(code)}, {"code": 'commitment', "name": 'Cam kết', "en": "Commitment", "file": "{}_commitment.docx".format(code), "pdf": "{}_commitment.pdf".format(code)}, {"code": 'pawn', "name": 'Cầm cố', "en": "Pawn", "file": "{}_pawn.docx".format(code), "pdf": "{}_pawn.pdf".format(code)}, {"code": 'confirmation', "name": 'Xác nhận', "en": "Confirmation", "file": "{}_confirmation.docx".format(code), "pdf": "{}_confirmation.pdf".format(code)}] # update contract contract = Contract.objects.filter(application__code=code).first() if contract: contract.document = arr else: application = Application.objects.filter(code=code).first() contract = Contract(application=application, content="{} contract".format(code), document=arr) # save contract.save() return Response(status = status.HTTP_200_OK)