diff --git a/app/contract.py b/app/contract.py deleted file mode 100644 index 99a145a2..00000000 --- a/app/contract.py +++ /dev/null @@ -1,344 +0,0 @@ -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) diff --git a/app/document_generator.py b/app/document_generator.py index 1faaf680..dbb715ac 100644 --- a/app/document_generator.py +++ b/app/document_generator.py @@ -11,6 +11,7 @@ from django.apps import apps from num2words import num2words from django.conf import settings from app.models import Document_Configuration +from decimal import Decimal # ============================================================================= # Constants @@ -275,8 +276,12 @@ class DocumentGenerator: fmt_type = fmt.get("type") if isinstance(fmt, dict) else fmt if fmt_type == "currency": try: - num_val = int(round(float(val), 0)) - return "{:,}".format(num_val).replace(",", ".") + num_val = round(float(val), 2) + if Decimal(num_val) == Decimal(int(num_val)): + return "{:,}".format(int(num_val)).replace(",", ".") + else: + s = f"{num_val:,.2f}" + return s.replace(",", "X").replace(".", ",").replace("X", ".") except Exception: return str(val) if fmt_type == "date":