changes
This commit is contained in:
344
app/contract.py
344
app/contract.py
@@ -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ẻ <meta charset="utf-8"> vào đầu
|
|
||||||
html_with_encoding = f"""<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{html}
|
|
||||||
</body>
|
|
||||||
</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)
|
|
||||||
@@ -11,6 +11,7 @@ from django.apps import apps
|
|||||||
from num2words import num2words
|
from num2words import num2words
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from app.models import Document_Configuration
|
from app.models import Document_Configuration
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Constants
|
# Constants
|
||||||
@@ -275,8 +276,12 @@ class DocumentGenerator:
|
|||||||
fmt_type = fmt.get("type") if isinstance(fmt, dict) else fmt
|
fmt_type = fmt.get("type") if isinstance(fmt, dict) else fmt
|
||||||
if fmt_type == "currency":
|
if fmt_type == "currency":
|
||||||
try:
|
try:
|
||||||
num_val = int(round(float(val), 0))
|
num_val = round(float(val), 2)
|
||||||
return "{:,}".format(num_val).replace(",", ".")
|
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:
|
except Exception:
|
||||||
return str(val)
|
return str(val)
|
||||||
if fmt_type == "date":
|
if fmt_type == "date":
|
||||||
|
|||||||
Reference in New Issue
Block a user