From 8d095225fed9a9b419cdc852319694fd48a8c78e Mon Sep 17 00:00:00 2001 From: P3ngSaM <61768364+P3ngSaM@users.noreply.github.com> Date: Tue, 8 Aug 2023 16:38:07 +0800 Subject: [PATCH] changes --- App/Router/ModelRouter.py | 42 ++----- App/Router/ScoreRouter.py | 114 ++++++++++++++++++ Utils/File/template/中小商业企业信用模型.xlsx | Bin 0 -> 24599 bytes main.py | 4 +- 4 files changed, 129 insertions(+), 31 deletions(-) create mode 100644 App/Router/ScoreRouter.py create mode 100644 Utils/File/template/中小商业企业信用模型.xlsx diff --git a/App/Router/ModelRouter.py b/App/Router/ModelRouter.py index a560f3b..574975e 100644 --- a/App/Router/ModelRouter.py +++ b/App/Router/ModelRouter.py @@ -4,15 +4,13 @@ import os import numpy as np import openpyxl import pandas as pd -import pythoncom -import xlrd +import xlwings as xw from openpyxl import load_workbook from openpyxl.utils import get_column_letter from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, BackgroundTasks from openpyxl.worksheet.datavalidation import DataValidation from starlette.background import BackgroundTask from starlette.responses import FileResponse -from win32com.client import Dispatch from App.Schemas import ModelSchemas from Utils.DataBase.MongoHelperUtils import MongoHelper, get_mongodb @@ -256,7 +254,7 @@ async def func(background_tasks: BackgroundTasks, schemas: ModelSchemas.ModelSco raise HTTPException(status_code=404, detail="该模型不存在") fid = result.get('模型ID') file = mongo_db.get_file(db='中小商会企业信用评级', bucket='模型文件', fid=str(fid)) - file_name = "{}.xlsx".format('中小商业企业信用模型') + file_name = "{}.xlsx".format('中小商业企业信用模型2') path = os.path.join(os.getcwd(), 'Utils', 'File', 'generate', file_name) myfile = open(path, mode='wb') myfile.write(file) @@ -315,22 +313,19 @@ async def func(background_tasks: BackgroundTasks, schemas: ModelSchemas.ModelSco else: value = backtrack_data.get(cell_name) backtrack_sheet[val_cell] = value - wb.save(path) + wb.save('1.xlsx') - def just_open(filename): - # 解决读取公式计算数据为None的问题 - pythoncom.CoInitialize() - xlApp = Dispatch("Excel.Application") - xlApp.Visible = False - xlApp.DisplayAlerts = 0 - xlBook = xlApp.Workbooks.Open(filename) - xlBook.SaveAs(filename) - xlBook.Close() - - just_open(path) - - wb = openpyxl.load_workbook(path, data_only=True) + app = xw.App(visible=False, add_book=False) + # 不显示Excel消息框 + app.display_alerts = False + # 关闭屏幕更新,可加快宏的执行速度 + app.screen_updating = False + xwb = app.books.open('1.xlsx') + xwb.save() + xwb.close() + app.quit() + wb = load_workbook(path, data_only=True) sheet_01 = wb['中小商业企业信用模型'] index_data = [ {"指标": row[2].value, "数值": row[3].value, "单位": row[4].value, @@ -505,19 +500,8 @@ async def func(background_tasks: BackgroundTasks, pid: int = 123456, f.write(stream) return path - def just_open(filename): - # 解决读取公式计算数据为None的问题 - pythoncom.CoInitialize() - xlApp = Dispatch("Excel.Application") - xlApp.Visible = False - xlBook = xlApp.Workbooks.Open(filename) - xlBook.Save() - xlBook.Close() - file_path = create_file(file) - just_open(file_path) - wb = openpyxl.load_workbook(file_path, data_only=True) sheet_01 = wb['中小商业企业信用模型'] diff --git a/App/Router/ScoreRouter.py b/App/Router/ScoreRouter.py new file mode 100644 index 0000000..2eb56c5 --- /dev/null +++ b/App/Router/ScoreRouter.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +import os +import shutil + +import xlwings as xw +from openpyxl import load_workbook +from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks +from App.Schemas import ModelSchemas +from Utils.DataBase.MongoHelperUtils import MongoHelper, get_mongodb + +router = APIRouter( + prefix="/api/model_score" +) + + +def del_file(path): + os.remove(path) + + +@router.post("/model_score_reusult", summary="提交模型打分所需数据返回评级结果", tags=["评级结果"]) +async def func(background_tasks: BackgroundTasks, schemas: ModelSchemas.ModelScoreData): + # 复制一份文件到指定文件夹 + temp_file = os.path.join(os.getcwd(), 'Utils', 'File', 'template', '中小商业企业信用模型.xlsx') + dst_folder = os.path.join(os.getcwd(), 'Utils', 'File', 'generate') + shutil.copy(temp_file, dst_folder) + path = os.path.join(os.getcwd(), 'Utils', 'File', 'generate', '中小商业企业信用模型.xlsx') + # 打开模型excel + wb = load_workbook(path) + # 将经营问卷填入文件 + business_sheet = wb['经营问卷'] + business_data = schemas.经营问卷.dict() + business_sheet_rows = business_sheet.max_row + for i in range(2, business_sheet_rows + 1): + key_cell = 'A{}'.format(i) + val_cell = 'D{}'.format(i) + cell_name = business_sheet[key_cell].value + if cell_name == '对外服务总次数(包括电话咨询、客户支持、产品售后等)': + value = business_data.get('对外服务总次数') + else: + value = business_data.get(cell_name) + business_sheet[val_cell] = value + + # 财务问卷填入文件 + financial_sheet = wb['财务问卷'] + financial_data = schemas.财务问卷.dict() + financial_sheet_rows = financial_sheet.max_row - 5 + for j in range(2, financial_sheet_rows + 1): + key_cell = 'B{}'.format(j) + val1_cell = 'C{}'.format(j) + val2_cell = 'D{}'.format(j) + val3_cell = 'E{}'.format(j) + cell_name = financial_sheet[key_cell].value + if cell_name == '减:累计折旧': + value = financial_data.get('累计折旧') + else: + value = financial_data.get(cell_name) + financial_sheet[val1_cell] = value[0] + financial_sheet[val2_cell] = value[1] + financial_sheet[val3_cell] = value[2] + audit = financial_data.get('是否审计') + financial_sheet['B35'] = audit + firm = financial_data.get('会计事务所') + financial_sheet['B36'] = firm + + # 背调数据填入文件 + backtrack_sheet = wb['背调接口'] + backtrack_data = schemas.背调接口.dict() + backtrack_sheet_rows = backtrack_sheet.max_row + for i in range(2, backtrack_sheet_rows + 1): + key_cell = 'A{}'.format(i) + val_cell = 'C{}'.format(i) + cell_name = backtrack_sheet[key_cell].value + if cell_name == '开庭公告(被告-合同纠纷、劳动争议)': + value = backtrack_data.get('开庭公告被告合同纠纷劳动争议') + elif cell_name == '行政处罚(警告、通报批评、罚款)': + value = backtrack_data.get('行政处罚警告通报批评罚款') + elif cell_name == '行政处罚(没收违法所得、没收非法财务...)': + value = backtrack_data.get('行政处罚没收违法所得没收非法财务') + else: + value = backtrack_data.get(cell_name) + backtrack_sheet[val_cell] = value + wb.save('1.xlsx') + + app = xw.App(visible=False, add_book=False) + # 不显示Excel消息框 + app.display_alerts = False + # 关闭屏幕更新,可加快宏的执行速度 + app.screen_updating = False + xwb = app.books.open('1.xlsx') + xwb.save() + xwb.close() + app.quit() + + wb = load_workbook('1.xlsx', data_only=True) + sheet_01 = wb['中小商业企业信用模型'] + index_data = [ + {"指标": row[2].value, "数值": row[3].value, "单位": row[4].value, + "权重": row[7].value, "得分": row[8].value} for row in sheet_01.iter_rows()] + index_data = index_data[2:42] + + rating_result = { + "级别": sheet_01.cell(43, 6).value, + "总分": round(sheet_01.cell(43, 9).value, 2) + } + + background_tasks.add_task(del_file, path) + background_tasks.add_task(del_file, '1.xlsx') + return { + "message": "计算成功", + "data": { + "评级结果": rating_result, + "指标数值与得分": index_data + } + } diff --git a/Utils/File/template/中小商业企业信用模型.xlsx b/Utils/File/template/中小商业企业信用模型.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4baab65a264def6741e9353e6cd6d6665caa66dc GIT binary patch literal 24599 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 e)