import os import io import time import json import random import datetime import traceback import fitz import shutil import requests from openpyxl import Workbook from django.utils import timezone # from django.http import HttpResponse from django.db.models import Q from rest_framework.permissions import IsAuthenticated from webargs import fields, validate from webargs.djangoparser import use_args, parser from settings import conf from common import response from common.mixins import GenericView,DocGenericView from common.tools.file_tools import file_write from common.redis_cache import redis_handler as rh from .models import ( # UploadDocRecords, DocStatus, PriorityApplication, GCAPRecords, AFCComparisonInfo, # AFCSEComparisonInfo, AFCSECMSInfo, HILComparisonInfo, # HILSEComparisonInfo, HILSECMSInfo, AFCCompareOfflineReport, HILCompareOfflineReport, AFCCACompareResult, AFCSECompareResult, HILCACompareResult, HILSECompareResult, AFCCACompareResultRecord, AFCSECompareResultRecord, HILCACompareResultRecord, HILSECompareResultRecord, HILAutoSettlement, AFCAutoSettlement, HILbankVerification, AFCbankVerification, MposReport, GenericOCRReport, InterfaceReport, HILOCRResult, HILSEOCRResult, AFCOCRResult, AFCSEOCRResult, HILCmsStatusInfo, AFCCmsStatusInfo ) from .named_enum import ErrorType, AutoResult, WholeResult, RPAResult, SystemName, RequestTeam from .mixins import DocHandler, MPOSHandler, PreSEHandler from . import consts from apps.account.authentication import OAuth2AuthenticationWithUser from celery_compare.tasks import compare, fsm_compare from prese.compare import get_empty_result import time class CustomDate(fields.Date): def _deserialize(self, value, attr, data, **kwargs): return value class CustomDecimal(fields.Decimal): def __init__(self, places_2=False, *args, **kwargs): self.places_2 = places_2 super().__init__(*args, **kwargs) def _deserialize(self, value, attr, data, **kwargs): if self.places_2: return format(self._validated(value), ".2f") else: return format(self._validated(value), "f") # return self._to_string(self._validated(value)) # restframework将request.body封装至request.data, webargs从request.data中获取参数 @parser.location_loader("data") def load_data(request, schema): return request.data employee_args = { 'application_id': fields.Str(required=True, validate=validate.Length(max=64)), 'business_type': fields.Str(required=True, validate=validate.Length(max=64)), } go_args = { 'image': fields.Raw(required=True), } usedcar_args = { 'vinNo': fields.Str(required=True, validate=validate.Length(max=128)), "manufactureDate": CustomDate(required=True), "firstRegistrationDate": CustomDate(required=True), } se_vehicle_args = { 'vehicleStatus': fields.Str(required=True, validate=validate.Length(max=16)), 'vehicleTransactionAmount': CustomDecimal(required=True), 'vinNo': fields.Str(required=True, validate=validate.Length(max=256)), 'dealer': fields.Str(required=True, validate=validate.Length(max=256)), 'showRoom': fields.Str(required=False), 'agencyDealer': fields.Str(required=False), 'option': CustomDecimal(required=False), 'msrp': CustomDecimal(required=False), 'totalAmount': CustomDecimal(required=False), } se_insurance_args = { 'insuredAmount': CustomDecimal(required=True), 'insuranceType': fields.Str(required=True, validate=validate.Length(max=16)), 'startDate': CustomDate(required=True), 'endDate': CustomDate(required=True), } se_associated_args = { 'service': fields.Str(required=True), 'amount': CustomDecimal(required=True), 'financedAmount': CustomDecimal(required=True) } se_payment_args = { 'term': fields.Int(required=True), 'amount': CustomDecimal(required=True, places_2=True) } se_bank_args = { 'bankName': fields.Str(required=True, validate=validate.Length(max=256)), 'branchName': fields.Str(required=True, validate=validate.Length(max=256)), 'applicantType': fields.Str(required=True, validate=validate.Length(max=16)), 'accountHolderName': fields.Str(required=True, validate=validate.Length(max=256)), 'accountNo': fields.Str(required=True, validate=validate.Length(max=256)), 'bankVerificationStatus': fields.Str(required=False, validate=validate.Length(max=128)), 'isAllDocUploaded': fields.Boolean(required=False) } se_quotationt_args = { 'totalLoanAmount': CustomDecimal(required=True), 'loanTerm': fields.Int(required=True), 'vehiclePrincipal': CustomDecimal(required=True), 'associatedServicePrincipal': CustomDecimal(required=False), 'mortgageType': fields.Str(required=True, validate=validate.Length(max=16)), 'associatedServiceInfo': fields.List(fields.Nested(se_associated_args), required=False), 'monthlyPaymentInfo': fields.List(fields.Nested(se_payment_args), required=True, validate=validate.Length(min=1)), } corporate_args = { 'customerType': fields.Str(required=True, validate=validate.OneOf(consts.CUSTOMER_TYPE)), 'customerChineseName': fields.Str(required=True, validate=validate.Length(max=256)), 'legalRepName': fields.Str(required=True, validate=validate.Length(max=64)), 'idNum': fields.Str(required=True, validate=validate.Length(max=256)), 'businessLicenseNo': fields.Str(required=True, validate=validate.Length(max=256)), 'taxRegistrationCode': fields.Str(required=True, validate=validate.Length(max=256)), "incorporationDate": CustomDate(required=True), "businessLicenseDueDate": CustomDate(required=True), "capitalRegAmount": CustomDecimal(required=True), # TODO 2位小数限制 } se_corporate_args = { 'customerType': fields.Str(required=True, validate=validate.OneOf(consts.CUSTOMER_TYPE)), 'companyName': fields.Str(required=True, validate=validate.Length(max=256)), 'firstIdType': fields.Str(required=True, validate=validate.Length(max=16)), 'firstIdNo': fields.Str(required=True, validate=validate.Length(max=256)), 'businessLicenseNo': fields.Str(required=True, validate=validate.Length(max=256)), 'organizationCreditCode': fields.Str(required=True, validate=validate.Length(max=256)), 'taxRegistrationCertificateNo': fields.Str(required=True, validate=validate.Length(max=256)), "establishmentDate": CustomDate(required=True), "incorporationDate": CustomDate(required=True), "businessLicenseDueDate": CustomDate(required=True), 'legalRepName': fields.Str(required=True, validate=validate.Length(max=64)), 'organizationType': fields.Str(required=True, validate=validate.Length(max=16)), 'fleetCustomer': fields.Boolean(required=False), 'beneficialOwnerName': fields.Str(required=False, validate=validate.Length(max=64)), 'beneficialOwnerIdType': fields.Str(required=False, validate=validate.Length(max=16)), 'beneficialOwnerIdNo': fields.Str(required=False, validate=validate.Length(max=256)), 'beneficialOwnerIdExpiryDate': CustomDate(required=False), } individual_args = { 'applicantType': fields.Str(required=True, validate=validate.OneOf(consts.APPLICANT_TYPE)), 'customerType': fields.Str(required=True, validate=validate.OneOf(consts.CUSTOMER_TYPE)), 'idType': fields.Str(required=True, validate=validate.OneOf(consts.ID_TYPE)), 'secondIdType': fields.Str(required=False, validate=validate.OneOf(consts.SECOND_ID_TYPE)), 'customerChineseName': fields.Str(required=True, validate=validate.Length(max=64)), 'idNum': fields.Str(required=True, validate=validate.Length(max=256)), 'secondIdNum': fields.Str(required=False, validate=validate.Length(max=256)), "idExpiryDate": CustomDate(required=True), "dateOfBirth": CustomDate(required=True), 'companyName': fields.Str(required=False, validate=validate.Length(max=256)), "registeredCapital": CustomDecimal(required=False), 'selfEmployedSubType': fields.Str(required=False, validate=validate.OneOf(consts.SUB_TYPE)), } se_individual_args = { 'customerType': fields.Str(required=True, validate=validate.OneOf(consts.CUSTOMER_TYPE)), 'applicantType': fields.Str(required=True, validate=validate.OneOf(consts.APPLICANT_TYPE)), 'customerName': fields.Str(required=True, validate=validate.Length(max=64)), 'idType': fields.Str(required=True, validate=validate.OneOf(consts.ID_TYPE)), 'idNum': fields.Str(required=True, validate=validate.Length(max=256)), 'secondIdType': fields.Str(required=False, validate=validate.OneOf(consts.SECOND_ID_TYPE)), 'secondIdNum': fields.Str(required=False, validate=validate.Length(max=256)), "dateOfBirth": CustomDate(required=True), "idExpiryDate": CustomDate(required=True), 'nationality': fields.Str(required=False, validate=validate.Length(max=64)), 'countryregion': fields.Str(required=False, validate=validate.Length(max=64)), 'hukouProvince': fields.Str(required=False, validate=validate.Length(max=64)), 'hukouCity': fields.Str(required=False, validate=validate.Length(max=64)), 'residentialProvince': fields.Str(required=False, validate=validate.Length(max=64)), 'residentialCity': fields.Str(required=False, validate=validate.Length(max=64)), 'companyName': fields.Str(required=False, validate=validate.Length(max=256)), 'registeredCapital': CustomDecimal(required=False), 'selfEmployedSubType': fields.Str(required=False, validate=validate.Length(max=16)), } comment_args = { 'comment': fields.Str(required=True, validate=validate.Length(max=1024)), } compare_content = { 'uniqSeq': fields.Str(required=True, validate=validate.Length(max=128)), 'applicationId': fields.Str(required=True, validate=validate.Length(max=64)), 'applicationEntity': fields.Str(required=True, validate=validate.OneOf(consts.ENTITY)), 'customerType': fields.Str(required=True, validate=validate.OneOf(consts.CUSTOMER_TYPE)), "applicationVersion": fields.Int(required=True), 'vehicleStatus': fields.Str(required=True, validate=validate.OneOf(consts.VEHICLE_STATUS)), 'comments': fields.List(fields.Nested(comment_args), required=True), 'individualCusInfo': fields.List(fields.Nested(individual_args), required=True, validate=validate.Length(min=1, max=4)), 'usedCarInfo': fields.Nested(usedcar_args, required=False), 'corporateCusInfo': fields.Nested(corporate_args, required=False), } se_compare_content = { 'uniqSeq': fields.Str(required=True, validate=validate.Length(max=128)), 'applicationId': fields.Str(required=True, validate=validate.Length(max=64)), "applicationVersion": fields.Int(required=True), 'applicationEntity': fields.Str(required=True, validate=validate.OneOf(consts.ENTITY)), 'productGroup': fields.Str(required=False), 'productGroupID': fields.Str(required=False), 'customerType': fields.Str(required=True, validate=validate.OneOf(consts.CUSTOMER_TYPE)), "firstSubmmisonDate": CustomDate(required=True), 'propertyDocumentPolicy': fields.Str(required=False, validate=validate.Length(max=16)), 'fsmFlag': fields.Boolean(required=False), 'fsmSpecialCar': fields.Boolean(required=False), 'fsmBestPrice': fields.Boolean(required=False), 'isAutoSettlement': fields.Boolean(required=False), 'fsmLandingDealer': fields.Str(required=False, validate=validate.Length(max=1024)), 'individualCusInfo': fields.List(fields.Nested(se_individual_args), required=True, validate=validate.Length(min=1, max=4)), 'corporateCusInfo': fields.Nested(se_corporate_args, required=False), 'vehicleInfo': fields.Nested(se_vehicle_args, required=True), 'insuranceInfo': fields.Nested(se_insurance_args, required=True), 'bankInfo': fields.Nested(se_bank_args, required=True), 'quotationtInfo': fields.Nested(se_quotationt_args, required=True), } compare_args = { 'content': fields.Nested(compare_content, required=True) } se_compare_args = { 'content': fields.Nested(se_compare_content, required=True) } application_data_args = { 'applicationId': fields.Str(required=True, validate=validate.Length(max=64)), 'applicationStatus': fields.Str(required=False, validate=validate.Length(max=64)), 'fsm': fields.Boolean(required=False), } applicant_data_args = { # 'mainApplicantName': fields.Str(required=True, validate=validate.Length(max=16)), # 'coApplicantName': fields.Str(required=True, validate=validate.Length(max=16)), # 'guarantor1Name': fields.Str(required=True, validate=validate.Length(max=16)), # 'guarantor2Name': fields.Str(required=True, validate=validate.Length(max=16)), 'mainApplicantName': fields.Str(required=False), 'coApplicantName': fields.Str(required=False), 'guarantor1Name': fields.Str(required=False), 'guarantor2Name': fields.Str(required=False), } document_args = { 'documentName': fields.Str(required=True, validate=validate.Length(max=255)), # Acceptance/Settlement/Contract Management 'documentScheme': fields.Str(required=True, validate=validate.Length(max=64)), 'businessType': fields.Str(required=True, validate=validate.Length(max=64)), # CO00001/CO00002 'uploadFinishTime': fields.DateTime(required=True), 'dataSource': fields.Str(required=True, validate=validate.Length(max=64)), # POS/EAPP/Econtract 'metadataVersionId': fields.Str(required=True, validate=validate.Length(max=64)), 'password': fields.Str(required=False, validate=validate.Length(max=16)), } doc_upload_args = { 'applicationData': fields.Nested(application_data_args, required=True), 'applicantData': fields.Nested(applicant_data_args, required=False), 'document': fields.Nested(document_args, required=True), } doc_list_args = { 'page': fields.Int(required=False, missing=consts.PAGE_DEFAULT, validate=lambda val: val >= 1), 'page_size': fields.Int(required=False, missing=consts.PAGE_SIZE_DEFAULT, validate=lambda val: val >= 1), 'status': fields.Int(required=False, validate=validate.OneOf(DocStatus.get_value_lst())), 'application_id': fields.Str(required=False, validate=validate.Length(max=64)), 'data_source': fields.Str(required=False, validate=validate.OneOf(consts.DATA_SOURCE_LIST)), 'business_type': fields.Str(required=True, validate=validate.OneOf(consts.BUSINESS_TYPE_LIST)), 'upload_time_start': fields.Date(required=False), 'upload_time_end': fields.Date(required=False), 'create_time_start': fields.Date(required=False), 'create_time_end': fields.Date(required=False), } auto_list_args = { 'page': fields.Int(required=False, missing=consts.PAGE_DEFAULT, validate=lambda val: val >= 1), 'page_size': fields.Int(required=False, missing=consts.PAGE_SIZE_DEFAULT, validate=lambda val: val >= 1), 'business_type': fields.Str(required=True, validate=validate.OneOf(consts.BUSINESS_TYPE_LIST)), 'application_id': fields.Str(required=False, validate=validate.Length(max=64)), 'auto_result': fields.Int(required=False, validate=validate.OneOf(AutoResult.get_value_lst())), 'whole_result': fields.Int(required=False, validate=validate.OneOf(WholeResult.get_value_lst())), 'rpa_result': fields.Int(required=False, validate=validate.OneOf(RPAResult.get_value_lst())), 'get_case_from_ocr_time_start': fields.Date(required=False), 'get_case_from_ocr_time_end': fields.Date(required=False), 'activated_time_start': fields.Date(required=False), 'activated_time_end': fields.Date(required=False), 'comparison_time_start': fields.Date(required=False), 'comparison_time_end': fields.Date(required=False), 'is_fsm': fields.Int(required=False), } compare_result_args = { 'entity': fields.Str(required=True, validate=validate.OneOf(consts.BUSINESS_TYPE_LIST)), 'scheme': fields.Str(required=True, validate=validate.OneOf(consts.COMPARE_DOC_SCHEME_LIST)), 'id': fields.Int(required=False, validate=lambda val: val >= 1), 'case_id': fields.Str(required=True, validate=validate.Length(max=64)), 'auto': fields.Int(required=False), } upload_pdf_args = { 'pdf_file': fields.Raw(required=True), 'business_type': fields.Str(required=True), 'document_scheme': fields.Str(required=True), 'data_source': fields.Str(required=True), 'document_name': fields.Str(required=True), } application_information = { "SUBMIT_DATETIME": fields.DateTime(required=True), "STATUS": fields.Int(required=True), 'ENTITY': fields.Str(required=True, validate=validate.Length(max=100)), "RATING": fields.Int(required=True), "APPLICATION_ID": fields.Str(required=True, validate=validate.Length(max=100)), "APPLICATION_VERSION": fields.Int(required=True), "INTERMEDIATE_DECISION": fields.Int(required=True), } priority_doc_args = { 'APPLICATION_INFORMATION': fields.Nested(application_information, required=True) } compare_offline_args = { 'is_hil': fields.Boolean(required=True), 'case_number': fields.Str(required=True, validate=validate.Length(max=255)), 'request_team': fields.Str(required=True, validate=validate.Length(max=255)), 'request_trigger': fields.Str(required=True, validate=validate.Length(max=1024)), 'input_file': fields.Str(required=True, validate=validate.Length(max=2048)), 'transaction_start': fields.DateTime(required=True), 'transaction_end': fields.DateTime(required=True), 'successful_at_this_level': fields.Boolean(required=True), 'failure_reason': fields.Str(required=False), 'process_name': fields.Str(required=True, validate=validate.Length(max=1024)), 'total_fields': fields.Int(required=True), 'workflow_name': fields.Str(required=True, validate=validate.Length(max=1024)), } id_info_args = { 'idType': fields.Str(required=True, validate=validate.Length(max=32)), 'idNum': fields.Str(required=True, validate=validate.Length(max=64)), 'idExpiryDate': CustomDate(required=True), } info_args = { 'applicantType': fields.Str(required=True, validate=validate.Length(max=64)), 'customersubType': fields.Str(required=True, validate=validate.Length(max=32)), 'selfEmployedSubType': fields.Str(required=False, validate=validate.Length(max=32)), 'name': fields.Str(required=True, validate=validate.Length(max=64)), 'legalRepName': fields.Str(required=False, validate=validate.Length(max=64)), 'dateOfBirth': CustomDate(required=False), 'nationality': fields.Str(required=False, validate=validate.Length(max=64)), 'establishmentDate': CustomDate(required=False), 'IDInformation': fields.List(fields.Nested(id_info_args), required=True, validate=validate.Length(min=1)), } auto_approve_details = { 'aaType': fields.Str(required=False, validate=validate.Length(max=64)), 'policyComments': fields.Str(required=False), } financial_info = { 'vehiclePrice': CustomDecimal(required=True), 'grossPrice': CustomDecimal(required=True), 'associatedServicePrice': CustomDecimal(required=True), 'vehiclePrincipal': CustomDecimal(required=True), 'associatedServicePrincipal': CustomDecimal(required=True), 'originationPrincipal': CustomDecimal(required=True), 'totalDownPayment': CustomDecimal(required=True), 'vehicleDownPaymentRatio': CustomDecimal(required=True), 'optionAmount': CustomDecimal(required=True), 'sumOfMSRPAndOption': CustomDecimal(required=True), } payment_schedule = { 'no': fields.Int(required=True), 'grossRentalAmount': CustomDecimal(required=True), } associated_services = { 'associatedServices': fields.Str(required=False, validate=validate.Length(max=64)), 'price': CustomDecimal(required=False), 'financed': CustomDecimal(required=False), 'total': CustomDecimal(required=False), } vehicle_info = { 'vinNo': fields.Str(required=True, validate=validate.Length(max=64)), } bank_details = { 'bankName': fields.Str(required=True, validate=validate.Length(max=64)), 'accountHolderName': fields.Str(required=True, validate=validate.Length(max=64)), 'accountNo': fields.Str(required=True, validate=validate.Length(max=64)), } insurance_details = { 'insuranceType': fields.Str(required=True, validate=validate.Length(max=64)), 'insuranceAmount': fields.Str(required=True, validate=validate.Length(max=64)), 'startDate': CustomDate(required=True), 'endDate': CustomDate(required=True), } corporate_info = { 'hashCode': fields.Str(required=False, validate=validate.Length(max=64)), 'borrowerName': fields.Str(required=False, validate=validate.Length(max=64)), 'fiscalYear': fields.Int(required=False), 'totaAssets': CustomDecimal(required=False), 'totalLiabilitiesAndOwnersEquity': CustomDecimal(required=False), 'cashAndCashEquivalentAtEndOfPeriod': CustomDecimal(required=False), 'netProfit': CustomDecimal(required=False), } se_verification = { 'applicationNo': fields.Str(required=True, validate=validate.Length(max=64)), } se_cms_content = { 'financeCompany': fields.Str(required=True, validate=validate.Length(max=512)), 'contractNo': fields.Str(required=True, validate=validate.Length(max=64)), 'status': fields.Str(required=True, validate=validate.Length(max=64)), 'branch': fields.Str(required=True, validate=validate.Length(max=512)), 'fpCampaign': fields.Str(required=True, validate=validate.Length(max=512)), 'applicationVersion': fields.Int(required=True), 'submissionDate': CustomDate(required=True), 'mortgageType': fields.Str(required=True, validate=validate.Length(max=64)), 'dealerRegion': fields.Str(required=True, validate=validate.Length(max=64)), 'insuranceRealNameCity': fields.Boolean(required=True), 'totalFinanceAmount': CustomDecimal(required=True), 'terms': fields.Int(required=True), 'dealerName': fields.Str(required=True, validate=validate.Length(max=512)), 'tier': fields.Str(required=True, validate=validate.Length(max=64)), 'province': fields.Str(required=True, validate=validate.Length(max=64)), 'fapiaoIssuerDealer': fields.Str(required=False, validate=validate.Length(max=512)), 'customerName': fields.Str(required=True, validate=validate.Length(max=64)), 'customerIdNo': fields.Str(required=True, validate=validate.Length(max=64)), 'vehicleStatus': fields.Str(required=True, validate=validate.Length(max=64)), 'applicationSource': fields.Str(required=True, validate=validate.Length(max=64)), 'contractSource': fields.Str(required=True, validate=validate.Length(max=64)), 'applicationRating': fields.Int(required=False), 'applicantInformation': fields.List(fields.Nested(info_args), required=True, validate=validate.Length(min=1, max=4)), 'autoApprovedDetails': fields.Nested(auto_approve_details, required=True), 'financialInformation': fields.Nested(financial_info, required=True), 'paymentSchedule': fields.List(fields.Nested(payment_schedule), required=True, validate=validate.Length(min=1)), 'associatedServices': fields.List(fields.Nested(associated_services), required=True), 'vehicleInformation': fields.Nested(vehicle_info, required=True), 'bankAccountDetails': fields.Nested(bank_details, required=True), 'insuranceDetails': fields.Nested(insurance_details, required=True), 'corporateFinancialInformation': fields.Nested(corporate_info, required=True), 'settlemnetVerification': fields.Nested(se_verification, required=True), } se_cms_args = { 'content': fields.Nested(se_cms_content, required=True) } se_contract_content = { 'uniqSeq': fields.Str(required=True, validate=validate.Length(max=128)), 'applicationId': fields.Str(required=True, validate=validate.Length(max=64)), 'applicationEntity': fields.Str(required=True, validate=validate.OneOf(consts.ENTITY)), "applicationVersion": fields.Int(required=True), } se_contract_args = { 'content': fields.Nested(se_contract_content, required=True) } result_item_args = { consts.HEAD_LIST[0]: fields.Str(required=True), consts.HEAD_LIST[1]: fields.Str(required=True), consts.HEAD_LIST[2]: fields.Str(required=True), consts.HEAD_LIST[3]: fields.Str(required=True), consts.HEAD_LIST[4]: fields.Str(required=True), consts.HEAD_LIST[5]: fields.Str(required=True), consts.HEAD_LIST[6]: fields.Str(required=True), consts.HEAD_LIST[7]: fields.Str(required=True), consts.HEAD_LIST[8]: fields.Str(required=True), consts.HEAD_LIST[9]: fields.Int(required=True), } result_update_args = { 'id': fields.Int(required=True), 'application_id': fields.Str(required=True, validate=validate.Length(max=64)), 'entity': fields.Str(required=True, validate=validate.OneOf(consts.BUSINESS_TYPE_LIST)), 'scheme': fields.Str(required=True, validate=validate.OneOf(consts.DOC_SCHEME_LIST)), 'whole_result': fields.Str(required=True), 'version': fields.Str(required=True), 'source': fields.Str(required=True), 'latest_compared_time': fields.Str(required=True), 'comments': fields.Str(required=True), 'result': fields.List(fields.Nested(result_item_args), required=True, validate=validate.Length(min=1)), } mpos_args = { 'type': fields.Int(required=True, validate=validate.OneOf(consts.MPOS_MAP)), 'file_base64_content': fields.List(fields.Str(), required=True, validate=validate.Length(min=1)), } class UploadDocView(GenericView, DocHandler): # permission_classes = [] # authentication_classes = [] permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # required_scopes = ['write'] # 上传(接收)文件接口 @use_args(doc_upload_args, location='data') def post(self, request, args): # interface_report pos/eapp/econtract to ocr start_time = time.time() application_data = args.get('applicationData') # applicant_data = args.get('applicantData') document = args.get('document') business_type = document.get('businessType') application_id = application_data.get('applicationId') # 包含FSM 激活状态 application_status = application_data.get('applicationStatus', '') fsm = application_data.get('fsm', False) document_scheme = document.get('documentScheme') data_source = document.get('dataSource') document_name = document.get('documentName', '') pwd = document.get('password', '') data_source = self.fix_data_source(data_source) document_scheme = self.fix_scheme(document_scheme) # fsm激活状态, 更新ocr_result 表fsm状态 self.running_log.info('[doc upload applicationId-{0}] [applicationStatus-{1}, activated-{2}]' .format(application_id, application_status, True if consts.FSM_ACTIVITED_STATUS.get(application_status) else False)) if consts.FSM_ACTIVITED_STATUS.get(application_status): result_class = None if business_type == consts.HIL_PREFIX: if document_scheme == RequestTeam.ACCEPTANCE.name: result_class = HILOCRResult elif document_scheme == RequestTeam.SETTLEMENT.name or document_scheme == RequestTeam.INSURANCE.name: result_class = HILSEOCRResult elif business_type == consts.AFC_PREFIX: if document_scheme == RequestTeam.ACCEPTANCE.name: result_class = AFCOCRResult elif document_scheme == RequestTeam.SETTLEMENT.name or document_scheme == RequestTeam.INSURANCE.name: result_class = AFCSEOCRResult ocr_result_obj = result_class.objects.filter(application_id=application_id).first() if ocr_result_obj: ocr_result_obj.fsm_activited = 1 ocr_result_obj.save() else: ocr_result_obj = result_class() ocr_result_obj.application_id = application_id ocr_result_obj.fsm_activited = 1 ocr_result_obj.save() self.running_log.info('[doc upload applicationId-{0}] [ocr result saved]'.format(application_id)) if data_source == consts.DATA_SOURCE_LIST[1]: if document_name.endswith('-证书.pdf') or document_name.endswith('-证书') or '-证书-bk-' in document_name: self.running_log.info('[doc upload success] [eapp license skip] [args={0}]'.format(args)) return response.ok() if data_source == consts.DATA_SOURCE_LIST[-1] and document_scheme == consts.DOC_SCHEME_LIST[1]: # 电子合同来源的压缩包直接返回,避免被ocr识别导致线上问题 if document_name.endswith('.zip') \ or document_name.endswith('.rar') \ or document_name.endswith('.ZIP') \ or document_name.endswith('.RAR'): self.running_log.info('[doc upload success] [SETTLEMENT ECONTRACT zip skip] [args={0}]'.format(args)) return response.ok() # 2. 根据业务类型分库存储 doc_class, prefix = self.get_doc_class(business_type) doc = doc_class.objects.create( metadata_version_id=document.get('metadataVersionId'), application_id=application_id, document_name=document_name, document_scheme=document_scheme, data_source=data_source, is_ovp_fsm=1 if fsm else 0, upload_finish_time=document.get('uploadFinishTime'), password=pwd if isinstance(pwd, str) and len(pwd) > 0 else None, ) # 3. 选择队列进入 is_priority = PriorityApplication.objects.filter(application_id=application_id, on_off=True).exists() is_zip = False classify_1 = 0 # 电子合同 Econtract or OVP(FSM) if data_source == consts.DATA_SOURCE_LIST[2] or data_source == consts.DATA_SOURCE_LIST[3]: if document_scheme == consts.DOC_SCHEME_LIST[1]: for keyword, classify_1_tmp in consts.ECONTRACT_KEYWORDS_MAP.get(prefix): if keyword in document_name: classify_1 = classify_1_tmp break # FSM合同:WEP/MSI/SC/SC2 elif data_source == consts.DATA_SOURCE_LIST[0] and document_scheme == consts.DOC_SCHEME_LIST[0]: for keyword, classify_1_tmp in consts.FSM_ECONTRACT_KEYWORDS_MAP.get(prefix): if keyword in document_name: classify_1 = classify_1_tmp break if document_name.endswith('.zip') or document_name.endswith('.rar') or document_name.endswith('.ZIP') \ or document_name.endswith('.RAR'): is_zip = True task = consts.SPLIT_STR.join([prefix, str(doc.id), str(classify_1)]) enqueue_res = rh.enqueue([task], is_priority, is_zip) self.running_log.info('[doc upload success] [args={0}] [business_type={1}] [doc_id={2}] ' '[is_priority={3}] [enqueue_res={4}] [is_fsm={5} [classify_1={6}]]'.format(args, prefix, doc.id, is_priority, enqueue_res, fsm, classify_1)) try: end_time = time.time() document.pop('uploadFinishTime', None) duration_second = int(end_time - start_time) InterfaceReport.objects.create( source=data_source, target=SystemName.OCR.name, body=json.dumps(args), response=None, status=True, # retry_times=None, duration=duration_second, ) except Exception as e: self.exception_log.exception('[upload view] [db save failed] [error={0}]'.format(traceback.format_exc())) return response.ok() post.openapi_doc = ''' tags: [doc] summary: POS系统上传文件信息 consumes: [application/json] produces: [application/json] parameters: - in: body name: body required: true schema: $ref: "#/definitions/Doc" responses: 200: description: ok schema: $ref: '#/definitions/ApiResponse' ''' class PriorityDocView(GenericView, DocHandler): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # 优先级订单接口 @use_args(priority_doc_args, location='data') def post(self, request, args): # interface_report gcap to ocr start_time = time.time() application_info = args.get('APPLICATION_INFORMATION') application_id = application_info.get('APPLICATION_ID') submit_datetime = application_info.get('SUBMIT_DATETIME') intermediate_decision = str(application_info.get('INTERMEDIATE_DECISION')) entity = application_info.get('ENTITY') if submit_datetime.utcoffset() is not None: submit_datetime = timezone.make_naive(submit_datetime, timezone.get_current_timezone()) GCAPRecords.objects.create( entity=entity, status=application_info.get('STATUS'), rating=application_info.get('RATING'), application_id=application_id, application_version=application_info.get('APPLICATION_VERSION'), intermediate_decision=intermediate_decision, submit_datetime=submit_datetime, ) if intermediate_decision not in consts.PRIORITY_WORDS: self.running_log.info('[priority doc skip] [args={0}]'.format(args)) return response.ok() _, created = PriorityApplication.objects.update_or_create(application_id=application_id, defaults={'on_off': True}) if created: doc_class, prefix = self.get_doc_class(entity) doc_ids = doc_class.objects.filter(application_id=application_id, status=DocStatus.INIT.value).values_list('id', flat=True) tasks_list = ['{0}{1}{2}'.format(prefix, consts.SPLIT_STR, doc_id) for doc_id in doc_ids] if not tasks_list: self.running_log.info( '[priority doc success] [args={0}]'.format(args)) else: enqueue_res = rh.enqueue(tasks_list, is_priority=True) # TODO 可能把压缩文件放入优先队列 self.running_log.info('[priority doc success] [args={0}] [tasks_list={1}] [enqueue_res={2}]'.format( args, tasks_list, enqueue_res)) try: end_time = time.time() duration_second = int(end_time - start_time) application_info.pop('SUBMIT_DATETIME', None) InterfaceReport.objects.create( source=SystemName.GCAP.name, target=SystemName.OCR.name, body=json.dumps(args), response=None, status=True, # retry_times=None, duration=duration_second, ) except Exception as e: self.exception_log.exception('[gcap view] [db save failed] [error={0}]'.format(traceback.format_exc())) return response.ok() post.openapi_doc = ''' tags: [doc] summary: GCAP提高申请单对应文件优先级 consumes: [application/json] produces: [application/json] parameters: - in: body name: body required: true schema: $ref: "#/definitions/Application" responses: 200: description: ok schema: $ref: '#/definitions/ApiResponse' ''' class CompareView(GenericView): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # pos上传比对信息接口 CA @use_args(compare_args, location='data') def post(self, request, args): # interface_report pos to ocr start_time = time.time() # 存库 content = args.get('content', {}) uniq_seq = content.get('uniqSeq') business_type = content.get('applicationEntity') application_id = content.get('applicationId') individual_cus_info = json.dumps(content.get('individualCusInfo')) usedcar_info = json.dumps(content.get('usedCarInfo')) if isinstance(content.get('usedCarInfo'), dict) else None corporate_cus_info = json.dumps(content.get('corporateCusInfo')) if isinstance( content.get('corporateCusInfo'), dict) else None comparison_class = HILComparisonInfo if business_type in consts.HIL_SET else AFCComparisonInfo comparison_class.objects.create( uniq_seq=uniq_seq, application_id=application_id, customer_type=content.get('customerType'), application_version=content.get('applicationVersion'), vehicle_status=content.get('vehicleStatus'), individual_cus_info=individual_cus_info, usedcar_info=usedcar_info, corporate_cus_info=corporate_cus_info, ) # 触发比对 compare.apply_async((application_id, business_type, uniq_seq, None, True, False), queue='queue_compare') try: end_time = time.time() duration_second = int(end_time - start_time) InterfaceReport.objects.create( source=SystemName.POS.name, target=SystemName.OCR.name, body=json.dumps(args), response=None, status=True, # retry_times=None, duration=duration_second, ) except Exception as e: self.exception_log.exception('[pos ca view] [db save failed] [error={0}]'.format(traceback.format_exc())) return response.ok() post.openapi_doc = ''' tags: [info] summary: POS上传CA比对信息 consumes: [application/json] produces: [application/json] parameters: - in: body name: body required: true schema: $ref: "#/definitions/Comparison" responses: 200: description: ok schema: $ref: '#/definitions/ApiResponse' ''' pre_fsm_url = conf.PRE_FSM_URL class SECompareView(GenericView, PreSEHandler): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # SE preSettlement @use_args(se_compare_args, location='data') def post(self, request, args): # interface_report pos to ocr start_time = time.time() log_base = '[prese]' # 存库 content = args.get('content', {}) business_type = content.get('applicationEntity') application_id = content.get('applicationId') uniq_seq = content.get('uniqSeq') bank_verify = content.get('bankInfo', {}).get('bankVerificationStatus', '') # fsm fsm_flag = content.get('fsmFlag', False) fsm_special_car = content.get('fsmSpecialCar', False) fsm_best_price = content.get('fsmBestPrice', False) fsm_landing_dealer = content.get('fsmLandingDealer') if fsm_special_car: compare_result = { "is_pass": False, "particulars": [{ "object_name": "", "fields": [{ "input": "", "ocr": "", "field_is_pass": False, "comments": "此申请为FSM 特殊申请,暂不支持预放款流程" }] }] } elif fsm_best_price: compare_result = { "is_pass": False, "particulars": [{ "object_name": "", "fields": [{ "input": "", "ocr": "", "field_is_pass": False, "comments": "此申请为FSM 特殊申请,暂不支持预放款流程" }] }] } elif fsm_flag and (not fsm_special_car or not fsm_best_price): # 调用Java pre fsm接口 try: self.running_log.info("{0} request java pre fsm api, url:{1}, body:{2}".format(log_base, pre_fsm_url, json.dumps(content))) headers = { 'Content-Type': 'application/json' } resp = requests.post(pre_fsm_url, headers=headers, json=content) self.running_log.info("{0} response from java pre fsm api, resp:{1}".format(log_base, resp.text)) result = json.loads(resp.text) compare_result = result.get("result") if not compare_result: compare_result = get_empty_result() except Exception as e: self.running_log.error("{0} pre fsm request to java error, url:{1}, param:{2}, errorMsg:{3}".format( log_base, pre_fsm_url, json.dumps(content), traceback.format_exc())) compare_result = get_empty_result() elif not fsm_flag: # 存库, 用于银行卡比对 try: bank_class = HILbankVerification if business_type in consts.HIL_SET else AFCbankVerification bank_obj = bank_class.objects.filter(application_id=application_id).first() if bank_obj is None and bank_verify == 'PASS': bank_class.objects.create( application_id=application_id, ) elif bank_obj is not None and bank_verify == 'PASS' and bank_obj.on_off is False: bank_obj.on_off = True bank_obj.save() elif bank_obj is not None and bank_verify != 'PASS' and bank_obj.on_off is True: bank_obj.on_off = False bank_obj.save() except Exception as e: self.running_log.info('{0} [bankCard verify save db error] [applicationEntity={1}] ' '[application_id={2}] [bank_status={3}] [error={4}]'.format( log_base, business_type, application_id, bank_verify, traceback.format_exc())) # preSettlement比对 compare_result = self.pre_compare_entrance(content) self.running_log.info('{0} [prese completed] [applicationEntity={1}] [application_id={2}] [uniq_seq={3}] ' '[result={4}]'.format(log_base, business_type, application_id, uniq_seq, compare_result)) try: end_time = time.time() duration_second = int(end_time - start_time) InterfaceReport.objects.create( source=SystemName.POS.name, target=SystemName.OCR.name, body=json.dumps(args), response=json.dumps(compare_result), status=True, # retry_times=None, duration=duration_second, ) except Exception as e: self.exception_log.exception('[pos pre view] [db save failed] [error={0}]'.format(traceback.format_exc())) return response.ok(data=compare_result) post.openapi_doc = ''' tags: [info] summary: POS上传SE比对信息 consumes: [application/json] produces: [application/json] parameters: - in: body name: body required: true schema: $ref: "#/definitions/SEComparison" responses: 200: description: ok schema: $ref: '#/definitions/ApiResponse' ''' class CompareOfflineView(GenericView): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # 线下文件夹比对结果上传接口 @use_args(compare_offline_args, location='data') def post(self, request, args): is_hil = args.get('is_hil', False) table = HILCompareOfflineReport if is_hil else AFCCompareOfflineReport table.objects.create( case_number=args.get('case_number'), request_team=args.get('request_team'), request_trigger=args.get('request_trigger'), input_file=args.get('input_file'), transaction_start=args.get('transaction_start'), transaction_end=args.get('transaction_end'), successful_at_this_level=args.get('successful_at_this_level'), failure_reason=args.get('failure_reason', ''), process_name=args.get('process_name'), total_fields=args.get('total_fields', 0), workflow_name=args.get('workflow_name'), ) return response.ok() post.openapi_doc = ''' tags: [info] summary: 线下文件夹比对结果上传 consumes: [application/json] produces: [application/json] parameters: - in: body name: body required: true schema: $ref: "#/definitions/ComparisonOffline" responses: 200: description: ok schema: $ref: '#/definitions/ApiResponse' ''' class DocView(DocGenericView, DocHandler): # 文件列表页 @use_args(doc_list_args, location='querystring') def get(self, request, args): page = args.get('page', consts.PAGE_DEFAULT) page_size = args.get('page_size', consts.PAGE_SIZE_DEFAULT) status = args.get('status') application_id = args.get('application_id') data_source = args.get('data_source') business_type = args.get('business_type') upload_time_start = args.get('upload_time_start') upload_time_end = args.get('upload_time_end') create_time_start = args.get('create_time_start') create_time_end = args.get('create_time_end') status_query = Q(status=status) if status is not None else Q() application_id_query = Q(application_id__contains=application_id) if application_id is not None else Q() data_source_query = Q(data_source=data_source) if data_source is not None else Q() upload_finish_time_query = Q(upload_finish_time__gte=upload_time_start, upload_finish_time__lt=upload_time_end + datetime.timedelta(days=1)) \ if upload_time_start is not None and upload_time_end is not None else Q() create_time_query = Q(create_time__gte=create_time_start, create_time__lt=create_time_end + datetime.timedelta(days=1)) \ if create_time_start is not None and create_time_end is not None else Q() query = application_id_query & status_query & data_source_query & upload_finish_time_query & create_time_query val_tuple = ('id', 'application_id', 'upload_finish_time', 'create_time', 'document_scheme', 'data_source', 'status', 'duration', 'page_count') doc_class, prefix = self.get_doc_class(business_type) total = doc_class.objects.filter(query).count() start_index = page_size * (page - 1) end_index = page_size * page if start_index >= total > 0: raise self.invalid_params('页数不存在') doc_queryset = doc_class.objects.filter(query).values(*val_tuple).order_by('-create_time')[ start_index: end_index] # doc_list = self.get_doc_list(doc_queryset, prefix) for doc_dict in doc_queryset: tmp_scheme = consts.COMPARE_DOC_SCHEME_LIST[0] if doc_dict['document_scheme'] == consts.DOC_SCHEME_LIST[0] \ else consts.COMPARE_DOC_SCHEME_LIST[1] application_link = '{0}/showList/showList?entity={1}&scheme={2}&case_id={3}'.format( conf.BASE_URL, prefix, tmp_scheme, doc_dict['application_id']) doc_dict['target_url'] = application_link doc_id = doc_dict.get('id') doc_dict['excel_link'] = self.get_link(doc_id, business_type, file='excel') # total = len(doc_list) pagination = {'current': page, 'total': total, 'page_size': page_size} res = { 'pagination': pagination, 'doc_list': list(doc_queryset) } # 新增scheme、处理时长、文件页数,删除下载切图 # 新增链接跳转比对结果 self.running_log.info('[get doc list] [args={0}] [res={1}]'.format(args, res)) return response.ok(data=res) # 上传pdf,模拟下单 # @use_args(upload_pdf_args) def post(self, request): random_int = random.randint(0, consts.TIME_NUM) metadata_version_id = str(int(time.time()) - random_int) pdf_file = request.FILES.get('pdf_file') if isinstance(pdf_file.name, str): if not pdf_file.name.endswith('pdf') and not pdf_file.name.endswith('PDF'): self.invalid_params(msg='invalid params: not a PDF file') business_type = request.POST.get('business_type', '') document_scheme = request.POST.get('document_scheme', '') data_source = request.POST.get('data_source', '') document_name = request.POST.get('document_name', '') fsm = request.POST.get('is_fsm', 'N') args = {'business_type':business_type,'document_scheme':document_scheme,'data_source':data_source,'document_name':document_name,'pdf_file':pdf_file,'fsm':fsm} # business_type = random.choice(consts.BUSINESS_TYPE_LIST) # business_type = consts.BUSINESS_TYPE_LIST[0] tmp_save_path = os.path.join(conf.DATA_DIR, business_type, '{0}.pdf'.format(metadata_version_id)) file_write(pdf_file, tmp_save_path) try: file = fitz.Document(tmp_save_path) except Exception as e: os.remove(tmp_save_path) raise self.invalid_params(msg='invalid params: not a PDF file') else: if not file.isPDF: file.close() os.remove(tmp_save_path) raise self.invalid_params(msg='invalid params: not a PDF file') # elif not self.xss_pass(file): # os.remove(tmp_save_path) # raise self.invalid_params(msg='invalid params: PDF file XSS') file.close() # 1. 上传信息记录 application_id = '{0}{1}'.format(consts.FIXED_APPLICATION_ID_PREFIX, metadata_version_id) upload_finish_time = timezone.now() # document_scheme = random.choice(consts.DOC_SCHEME_LIST) # document_scheme = consts.DOC_SCHEME_LIST[1] # data_source = random.choice(consts.DATA_SOURCE_LIST) # UploadDocRecords.objects.create( # metadata_version_id=metadata_version_id, # application_id=application_id, # main_applicant='', # co_applicant='', # guarantor_1='', # guarantor_2='', # document_name=application_id, # document_scheme=document_scheme, # business_type=business_type, # data_source=data_source, # upload_finish_time=upload_finish_time, # ) # 2. 根据业务类型分库存储 doc_class, prefix = self.get_doc_class(business_type) doc = doc_class.objects.create( metadata_version_id=metadata_version_id, application_id=application_id, # main_applicant='', # co_applicant='', # guarantor_1='', # guarantor_2='', is_ovp_fsm=1 if fsm == 'Y' else 0, document_name=application_id, document_scheme=document_scheme, data_source=data_source, upload_finish_time=upload_finish_time, ) # 3.pdf文件移动 save_dir_path = os.path.join(conf.DATA_DIR, business_type, consts.TMP_DIR_NAME, str(doc.id)) save_file_path = os.path.join(save_dir_path, '{0}.pdf'.format(doc.id)) os.makedirs(save_dir_path, exist_ok=True) # file_write(pdf_file, save_file_path) shutil.move(tmp_save_path, save_file_path) # 4. 选择队列进入 is_priority = False classify_1 = 0 # 电子合同 Econtract or OVP(FSM) if data_source == consts.DATA_SOURCE_LIST[2] or data_source == consts.DATA_SOURCE_LIST[3]: if document_scheme == consts.DOC_SCHEME_LIST[1]: for keyword, classify_1_tmp in consts.ECONTRACT_KEYWORDS_MAP.get(prefix): if keyword in document_name: classify_1 = classify_1_tmp break # FSM合同:WEP/MSI/SC elif data_source == consts.DATA_SOURCE_LIST[0] and document_scheme == consts.DOC_SCHEME_LIST[0]: for keyword, classify_1_tmp in consts.FSM_ECONTRACT_KEYWORDS_MAP.get(prefix): if keyword in document_name: classify_1 = classify_1_tmp break # tasks = ['{0}{1}{2}'.format(prefix, consts.SPLIT_STR, doc.id)] task = consts.SPLIT_STR.join([prefix, str(doc.id), str(classify_1)]) enqueue_res = rh.enqueue([task], is_priority) self.running_log.info('[mock doc upload success] [args={0}] [business_type={1}] [doc_id={2}] ' '[is_priority={3}] [enqueue_res={4}]'.format(args, prefix, doc.id, is_priority, enqueue_res)) data = {'excel_path': os.path.join(save_dir_path, '{0}.xlsx'.format(doc.id))} return response.ok(data=data) class CompareResultView(GenericView): # permission_classes = [] # authentication_classes = [] # permission_classes = [IsAuthenticated] # authentication_classes = [OAuth2AuthenticationWithUser] # 获取比对结果 @use_args(compare_result_args, location='querystring') def get(self, request, args): result_id = args.get('id', None) entity = args.get('entity') scheme = args.get('scheme') case_id = args.get('case_id') is_auto = args.get('auto') if is_auto == 1: result_table = HILAutoSettlement if entity == consts.HIL_PREFIX else AFCAutoSettlement if result_id is not None: result_obj = result_table.objects.filter(id=result_id).first() else: result_obj = result_table.objects.filter(application_id=case_id).first() if result_obj is None: whole_result = '' latest_compared_time = '' else: whole_result = consts.RESULT_Y if result_obj.ocr_auto_result_pass else consts.RESULT_N latest_compared_time = '' if result_obj.ocr_latest_comparison_time is None else result_obj.ocr_latest_comparison_time.strftime( '%Y-%m-%d %H:%M') source = consts.INFO_SOURCE[1] version = comments = '' compare_result = { 'id': 0 if result_obj is None else result_obj.id, 'application_id': case_id, 'entity': entity, 'scheme': consts.DOC_SCHEME_LIST[0] if scheme == consts.COMPARE_DOC_SCHEME_LIST[0] else consts.DOC_SCHEME_LIST[1], 'whole_result': whole_result, 'latest_compared_time': latest_compared_time, 'source': source, 'version': version, 'comments': comments, 'result': [] if result_obj is None or not result_obj.ocr_auto_result else json.loads( result_obj.ocr_auto_result) } return response.ok(data=compare_result) if entity == consts.HIL_PREFIX: result_table = HILCACompareResult if scheme == consts.COMPARE_DOC_SCHEME_LIST[0] else HILSECompareResult else: result_table = AFCCACompareResult if scheme == consts.COMPARE_DOC_SCHEME_LIST[0] else AFCSECompareResult if result_id is not None: result_obj = result_table.objects.filter(id=result_id).first() else: result_obj = result_table.objects.filter(application_id=case_id).first() if result_obj is None: whole_result = '' else: whole_result = consts.RESULT_Y if result_obj.is_finish else consts.RESULT_N if result_obj is None or not isinstance(result_obj.comments, str): comments = '' else: comments = result_obj.comments if result_obj is None or not isinstance(result_obj.version, str): source = '' version = '' else: source, version = result_obj.version.split(consts.SPLIT_STR) compare_result = { 'id': 0 if result_obj is None else result_obj.id, 'application_id': case_id, 'entity': entity, 'scheme': consts.DOC_SCHEME_LIST[0] if scheme == consts.COMPARE_DOC_SCHEME_LIST[0] else consts.DOC_SCHEME_LIST[1], 'whole_result': whole_result, 'latest_compared_time': '' if result_obj is None else result_obj.update_time.strftime('%Y-%m-%d %H:%M'), 'source': source, 'version': version, 'comments': comments, 'result': [] if result_obj is None else json.loads(result_obj.result) } return response.ok(data=compare_result) # if len(result_str_list) == 0: # compare_result_list = [] # else: # compare_result_list = json.loads(result_str_list[0]) # # if len(compare_result_list) == 0: # body_html = "<h1>没有比对结果</h1>" # else: # head_content = ''.join(['<th>{0}</th>'.format(head_name) for head_name in consts.HEAD_LIST]) # head_html = '<tr>{0}</tr>'.format(head_content) # row_html_list = [] # for row_dict in compare_result_list: # row_list = [row_dict.get(head, '') for head in consts.HEAD_LIST] # row_content = ''.join(['<td>{0}</td>'.format(row_str) for row_str in row_list]) # row_html = '<tr>{0}</tr>'.format(row_content) # row_html_list.append(row_html) # content_html = ''.join(row_html_list) # body_html = '<table border="1">{0}{1}</table>'.format(head_html, content_html) # # html = """ # <!DOCTYPE html> # <html> # <head> # <meta charset="utf-8"> # <title>比对结果</title> # </head> # <body> # {0} # </body> # </html> # """.format(body_html) # return HttpResponse(html) # 比对结果更新 @use_args(result_update_args, location='data') def post(self, request, args): result_id = args.get('id') case_id = args.get('application_id') update_time = args.get('latest_compared_time') scheme = args.get('scheme') entity = args.get('entity') whole_result = args.get('whole_result') if entity == consts.HIL_PREFIX: result_table = HILCACompareResult if scheme == consts.DOC_SCHEME_LIST[0] else HILSECompareResult record_table = HILCACompareResultRecord if scheme == consts.DOC_SCHEME_LIST[0] else HILSECompareResultRecord else: result_table = AFCCACompareResult if scheme == consts.DOC_SCHEME_LIST[0] else AFCSECompareResult record_table = AFCCACompareResultRecord if scheme == consts.DOC_SCHEME_LIST[0] else AFCSECompareResultRecord if result_id is not None: result_obj = result_table.objects.filter(id=result_id).first() else: result_obj = result_table.objects.filter(application_id=case_id).first() if result_obj is None: return response.ok() result_str = json.dumps(args.get('result', [])) is_finish = whole_result == consts.RESULT_Y compare_count = 0 failed_count = 0 reason_dict = {} for result in args.get('result', []): compare_count += 1 if result.get(consts.HEAD_LIST[6]) == consts.RESULT_N: failed_count += 1 error_type = result.get(consts.HEAD_LIST[-1], '') if error_type in reason_dict: reason_dict[error_type] = reason_dict[error_type] + 1 else: reason_dict[error_type] = 1 record_table.objects.create( application_id=case_id, is_finish=is_finish, compare_count=compare_count, failed_count=failed_count, reason1_count=reason_dict.get(0, 0), reason2_count=reason_dict.get(1, 0), reason3_count=reason_dict.get(2, 0), reason4_count=reason_dict.get(3, 0), reason5_count=reason_dict.get(4, 0), reason6_count=reason_dict.get(5, 0), reason7_count=reason_dict.get(6, 0), reason8_count=reason_dict.get(7, 0), reason9_count=reason_dict.get(8, 0), reason10_count=reason_dict.get(9, 0), result=result_str, comments=args.get('comments', ''), ) if update_time == result_obj.update_time.strftime('%Y-%m-%d %H:%M'): result_obj.result = result_str result_obj.comments = args.get('comments', '') # result_obj.update_time = result_obj.update_time result_obj.save() return response.ok() else: whole_result = consts.RESULT_Y if result_obj.is_finish else consts.RESULT_N if isinstance(result_obj.comments, str): comments = result_obj.comments else: comments = '' if isinstance(result_obj.version, str): source, version = result_obj.version.split(consts.SPLIT_STR) else: source = '' version = '' compare_result = { 'id': result_obj.id, 'application_id': case_id, 'entity': entity, 'scheme': consts.DOC_SCHEME_LIST[0] if scheme == consts.COMPARE_DOC_SCHEME_LIST[0] else consts.DOC_SCHEME_LIST[1], 'whole_result': whole_result, 'latest_compared_time': result_obj.update_time.strftime('%Y-%m-%d %H:%M'), 'source': source, 'version': version, 'comments': comments, 'result': json.loads(result_obj.result) } return response.need_update(data=compare_result) class ResourcesView(GenericView): permission_classes = [] authentication_classes = [] def get(self, request): error_type_map = ErrorType.get_mappings() auto_result_map = AutoResult.get_mappings() whole_result_map = WholeResult.get_mappings() rpa_result_map = RPAResult.get_mappings() error_type = [{'label': v, 'value': k} for k, v in error_type_map.items()] auto_result = [{'label': v, 'value': k} for k, v in auto_result_map.items()] whole_result = [{'label': v, 'value': k} for k, v in whole_result_map.items()] rpa_result = [{'label': v, 'value': k} for k, v in rpa_result_map.items()] resources = { 'error_type': error_type, 'auto_result': auto_result, 'whole_result': whole_result, 'rpa_result': rpa_result } return response.ok(data=resources) class SECMSView(GenericView): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # CMS上传比对信息接口 SE # @use_args(se_cms_args, location='data') def post(self, request): # interface_report cms to ocr start_time = time.time() args = request.data cms_info = args.get('content', {}) business_type = consts.AFC_PREFIX if cms_info.get('financeCompany', '').startswith( '宝马') else consts.HIL_PREFIX src_application_id = cms_info.get('settlemnetVerification', {}).get('applicationNo', '') application_id = src_application_id[:src_application_id.rfind('-')] # auto flag is_auto = cms_info.get('AutoSettlement', False) # fsm flag fsm_contract = cms_info.get('FSMContract', False) is_fsm=1 if fsm_contract else 0 auto_class = HILAutoSettlement if business_type in consts.HIL_SET else AFCAutoSettlement auto_obj = auto_class.objects.filter(application_id=application_id).first() if is_auto: # 加入优先级队列 PriorityApplication.objects.update_or_create( application_id=application_id, defaults={'on_off': True}) # 加入auto表 if auto_obj is None: auto_class.objects.create( application_id=application_id, is_fsm=is_fsm, ) elif auto_obj.on_off is False: auto_obj.on_off = True auto_obj.save() else: if auto_obj is not None and auto_obj.on_off is True: auto_obj.on_off = False auto_obj.save() # 比对信息存储 content_str = json.dumps(cms_info) comparison_class = HILSECMSInfo if business_type in consts.HIL_SET else AFCSECMSInfo comparison_class.objects.create( application_id=application_id, content=content_str, ) # 检查是否fsm流程(SE) fsm_best_price = cms_info.get('FSMBestPrice', False) if fsm_contract: # 记录fsm 流程的cms 提交 try: cms_status_class = HILCmsStatusInfo if business_type in consts.HIL_SET else AFCCmsStatusInfo cms_status_info = cms_status_class.objects.filter(application_id=application_id).first() if cms_status_info: cms_status_info.is_fsm = 1 cms_status_info.update_time = datetime.datetime.now() cms_status_info.save() else: cms_status_info = cms_status_class() cms_status_info.application_id = application_id cms_status_info.business_type = business_type cms_status_info.is_fsm = 1 cms_status_info.update_time = datetime.datetime.now() cms_status_info.create_time = datetime.datetime.now() cms_status_info.save() except Exception as e: self.exception_log.exception( '[cms view] [cms_status_info db save failed] [error={0}]'.format(traceback.format_exc())) fsm_compare.apply_async((application_id, business_type, None, None, False, True), queue='queue_compare') else: # 触发比对 compare.apply_async((application_id, business_type, None, None, False, True), queue='queue_compare') try: end_time = time.time() duration_second = int(end_time - start_time) InterfaceReport.objects.create( source=SystemName.CMS.name, target=SystemName.OCR.name, body=json.dumps(args), response=None, status=True, # retry_times=None, duration=duration_second, ) except Exception as e: self.exception_log.exception('[cms view] [db save failed] [error={0}]'.format(traceback.format_exc())) return response.ok() post.openapi_doc = ''' tags: [info] summary: CMS上传比对信息 consumes: [application/json] produces: [application/json] parameters: - in: body name: body required: true schema: $ref: "#/definitions/CMS" responses: 200: description: ok schema: $ref: '#/definitions/ApiResponse' ''' class SEContractView(GenericView): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # pos上传e-contract信息接口 SE @use_args(se_contract_args, location='data') def post(self, request, args): # contract_info = args.get('content', {}) # application_id = contract_info.get('applicationId', '') # entity = contract_info.get('applicationEntity', '') # table_class = HILContract if entity == consts.HIL_PREFIX else AFCContract # table_class.objects.create(application_id=application_id) # forwarding_station.apply_async((application_id, entity), queue='queue_compare', countdown=conf.DELAY_SECONDS) self.running_log.info('[e-contract pos in] [args={0}]'.format(args)) return response.ok() class AutoSettlementView(GenericView): # permission_classes = [] # authentication_classes = [] # permission_classes = [IsAuthenticated] # authentication_classes = [OAuth2AuthenticationWithUser] # 获取auto settlement列表 @use_args(auto_list_args, location='querystring') def get(self, request, args): page = args.get('page', consts.PAGE_DEFAULT) page_size = args.get('page_size', consts.PAGE_SIZE_DEFAULT) business_type = args.get('business_type') application_id = args.get('application_id') get_case_from_ocr_time_start = args.get('get_case_from_ocr_time_start') get_case_from_ocr_time_end = args.get('get_case_from_ocr_time_end') activated_time_start = args.get('activated_time_start') activated_time_end = args.get('activated_time_end') comparison_time_start = args.get('comparison_time_start') comparison_time_end = args.get('comparison_time_end') auto_result = args.get('auto_result', '') whole_result = args.get('whole_result', '') rpa_result = args.get('rpa_result', '') is_fsm = args.get('is_fsm') if isinstance(auto_result, int): auto_result = consts.RESULT_MAP.get(auto_result) if isinstance(whole_result, int): whole_result = consts.RESULT_MAP.get(whole_result) if isinstance(rpa_result, int): rpa_result = consts.RPA_RESULT_MAP.get(rpa_result) application_id_query = Q(application_id__contains=application_id) if application_id is not None else Q() auto_result_query = Q(ocr_auto_result_pass=auto_result) if not isinstance(auto_result, str) else Q() whole_result_query = Q(ocr_whole_result_pass=whole_result) if not isinstance(whole_result, str) else Q() rpa_result_query = Q(rpa_result=rpa_result) if not isinstance(rpa_result, str) else Q() time1_query = Q(rpa_get_case_from_ocr_time__gte=get_case_from_ocr_time_start, rpa_get_case_from_ocr_time__lt=get_case_from_ocr_time_end + datetime.timedelta(days=1)) \ if get_case_from_ocr_time_start is not None and get_case_from_ocr_time_end is not None else Q() time2_query = Q(rpa_activated_time__gte=activated_time_start, rpa_activated_time__lt=activated_time_end + datetime.timedelta(days=1)) \ if activated_time_start is not None and activated_time_end is not None else Q() time3_query = Q(ocr_latest_comparison_time__gte=comparison_time_start, ocr_latest_comparison_time__lt=comparison_time_end + datetime.timedelta(days=1)) \ if comparison_time_start is not None and comparison_time_end is not None else Q() is_fsm_query = Q(is_fsm=is_fsm) if is_fsm is not None else Q() query = application_id_query & auto_result_query & whole_result_query & rpa_result_query \ & time1_query & time2_query & time3_query & is_fsm_query auto_class = HILAutoSettlement if business_type in consts.HIL_SET else AFCAutoSettlement total = auto_class.objects.filter(query).count() start_index = page_size * (page - 1) end_index = page_size * page if start_index >= total > 0: raise self.invalid_params('页数不存在') val_tuple = ('application_id', 'ocr_latest_comparison_time', 'ocr_auto_result_pass', 'ocr_whole_result_pass', 'rpa_result', 'rpa_activated_time', 'rpa_get_case_from_ocr_time','is_fsm') auto_queryset = auto_class.objects.filter(query).values(*val_tuple).order_by( '-ocr_latest_comparison_time')[start_index: end_index] auto_link_base = '{0}/showList/showList?entity={1}&scheme={2}&case_id={3}&auto=1' for auto_dict in auto_queryset: auto_dict['ocr_auto_result_pass'] = consts.RE_RESULT_MAP.get(auto_dict.get('ocr_auto_result_pass')) auto_dict['ocr_whole_result_pass'] = consts.RE_RESULT_MAP.get(auto_dict.get('ocr_whole_result_pass')) auto_dict['rpa_result'] = consts.RE_RPA_RESULT_MAP.get(auto_dict.get('rpa_result')) auto_dict['target_url'] = auto_link_base.format( conf.BASE_URL, business_type, consts.COMPARE_DOC_SCHEME_LIST[1], auto_dict['application_id']) # total = len(doc_list) pagination = {'current': page, 'total': total, 'page_size': page_size} res = { 'pagination': pagination, 'auto_list': list(auto_queryset) } self.running_log.info('[get auto list] [args={0}] [res={1}]'.format(args, res)) return response.ok(data=res) class AutoSettlementExcelView(GenericView): # permission_classes = [] # authentication_classes = [] # permission_classes = [IsAuthenticated] # authentication_classes = [OAuth2AuthenticationWithUser] # 获取auto settlement excel @use_args(auto_list_args, location='querystring') def get(self, request, args): business_type = args.get('business_type') application_id = args.get('application_id') get_case_from_ocr_time_start = args.get('get_case_from_ocr_time_start') get_case_from_ocr_time_end = args.get('get_case_from_ocr_time_end') activated_time_start = args.get('activated_time_start') activated_time_end = args.get('activated_time_end') comparison_time_start = args.get('comparison_time_start') comparison_time_end = args.get('comparison_time_end') auto_result = args.get('auto_result', '') whole_result = args.get('whole_result', '') rpa_result = args.get('rpa_result', '') is_fsm = args.get('is_fsm') if isinstance(auto_result, int): auto_result = consts.RESULT_MAP.get(auto_result) if isinstance(whole_result, int): whole_result = consts.RESULT_MAP.get(whole_result) if isinstance(rpa_result, int): rpa_result = consts.RPA_RESULT_MAP.get(rpa_result) application_id_query = Q(application_id__contains=application_id) if application_id is not None else Q() auto_result_query = Q(ocr_auto_result_pass=auto_result) if not isinstance(auto_result, str) else Q() whole_result_query = Q(ocr_whole_result_pass=whole_result) if not isinstance(whole_result, str) else Q() rpa_result_query = Q(rpa_result=rpa_result) if not isinstance(rpa_result, str) else Q() time1_query = Q(rpa_get_case_from_ocr_time__gte=get_case_from_ocr_time_start, rpa_get_case_from_ocr_time__lt=get_case_from_ocr_time_end + datetime.timedelta(days=1)) \ if get_case_from_ocr_time_start is not None and get_case_from_ocr_time_end is not None else Q() time2_query = Q(rpa_activated_time__gte=activated_time_start, rpa_activated_time__lt=activated_time_end + datetime.timedelta(days=1)) \ if activated_time_start is not None and activated_time_end is not None else Q() time3_query = Q(ocr_latest_comparison_time__gte=comparison_time_start, ocr_latest_comparison_time__lt=comparison_time_end + datetime.timedelta(days=1)) \ if comparison_time_start is not None and comparison_time_end is not None else Q() is_fsm_query = Q(is_fsm=is_fsm) if is_fsm is not None else Q() query = application_id_query & auto_result_query & whole_result_query & rpa_result_query \ & time1_query & time2_query & time3_query & is_fsm_query auto_class = HILAutoSettlement if business_type in consts.HIL_SET else AFCAutoSettlement auto_queryset = auto_class.objects.filter(query).values_list(*consts.AUTO_WB_FIELD[0]).order_by( '-ocr_latest_comparison_time') wb = Workbook() ws = wb.active ws.append(consts.AUTO_WB_FIELD[1]) for row in auto_queryset: ws.append(row) io_content = io.BytesIO() # 创建在内存中处理对象 wb.save(io_content) wb.close() file_name = 'ocr_auto_records_{0}'.format(timezone.now().strftime('%Y-%m-%d_%H:%M:%S')) return response.excel_response(file_name, io_content) class MPOSView(GenericView, MPOSHandler): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # MPOS @use_args(mpos_args, location='data') def post(self, request, args): # interface_report mpos to ocr start_time = time.time() classify = args.get('type') result_list = [] image_count = 0 all_success = True for img_base64 in args.get('file_base64_content', []): image_count += 1 try: if classify in consts.LICENSE_CLASSIFY_SET_1: result = self.ocr1_process(conf.MPOS_URL1, img_base64) else: result = self.ocr2_process(conf.MPOS_URL2, classify, img_base64) result_list.extend(result) except Exception as e: all_success = False continue end_time = time.time() duration_second = int(end_time - start_time) try: MposReport.objects.create( doc_type=classify, image_count=image_count, status=all_success, duration=duration_second, ) except Exception as e: self.exception_log.exception('[mpos view] [db save failed] [error={0}]'.format(traceback.format_exc())) try: InterfaceReport.objects.create( source=SystemName.MPOS.name, target=SystemName.OCR.name, body=None, response=json.dumps(result_list), status=True, # retry_times=None, duration=duration_second, ) except Exception as e: self.exception_log.exception('[go view] [db save failed] [error={0}]'.format(traceback.format_exc())) return response.ok(data=result_list) class GoView(GenericView): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] @use_args(go_args, location='files') def post(self, request, args): # interface_report unknown to ocr result = None is_success = False start_time = time.time() try: files = [ ('img', ('file', args.get('image'), 'application/octet-stream')) ] go_result = requests.post(url=conf.GO_OCR_URL, files=files) except Exception as e: pass else: if go_result.status_code == 200: is_success = True result = go_result.json().get('data', '') finally: end_time = time.time() duration_second = int(end_time - start_time) try: GenericOCRReport.objects.create( status=is_success, duration=duration_second, ) except Exception as e: self.exception_log.exception('[go view] [db save failed] [error={0}]'.format(traceback.format_exc())) try: InterfaceReport.objects.create( source=SystemName.UNKNOWN.name, target=SystemName.OCR.name, body=None, response=json.dumps(result) if is_success else None, status=is_success, # retry_times=None, duration=duration_second, ) except Exception as e: self.exception_log.exception('[go view] [db save failed] [error={0}]'.format(traceback.format_exc())) if is_success: return response.ok(data=result) else: return response.error_msg(msg='识别错误') class EmployeeView(GenericView): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] @use_args(employee_args, location='data') def post(self, request, args): application_id = args.get('application_id') business_type = args.get('business_type') ocr_result_class = HILOCRResult if business_type in consts.HIL_SET else AFCOCRResult ocr_result_info = ocr_result_class.objects.filter(application_id=application_id).first() self.running_log.info('[query Employee] [application_id={0}] [business_type={1}] [ocr_result_info exist={2}]'.format(application_id, business_type, ocr_result_info is not None)) if not ocr_result_info: self.running_log.info('[query Employee] [application_id={0}] ocr_result none'.format(application_id)) return response.ok(data=False) bss_ocr_str = ocr_result_info.bss_ocr if bss_ocr_str is None: return response.ok(data=False) bss_ocr = json.loads(bss_ocr_str) self.running_log.info('[query Employee] [application_id={0}] [bss_ocr={1}]'.format(application_id, bss_ocr)) for one_bss in bss_ocr: income_keywords = one_bss.get('income_keywords') self.running_log.info('[query Employee] [application_id={0}] [income_keywords={1}]'.format(application_id, income_keywords)) if income_keywords is not None and len(income_keywords) > 0: return response.ok(data=True) return response.ok(data=False)