import os import time import json import random import datetime import fitz import shutil 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 from common.tools.file_tools import file_write from common.redis_cache import redis_handler as rh from .models import ( DocStatus, PriorityApplication, GCAPRecords, AFCComparisonInfo, AFCSEComparisonInfo, AFCSECMSInfo, HILComparisonInfo, HILSEComparisonInfo, HILSECMSInfo, AFCCompareOfflineReport, HILCompareOfflineReport, AFCCACompareResult, AFCSECompareResult, HILCACompareResult, HILSECompareResult, AFCCACompareResultRecord, AFCSECompareResultRecord, HILCACompareResultRecord, HILSECompareResultRecord, ) from .named_enum import ErrorType from .mixins import DocHandler from . import consts from apps.account.authentication import OAuth2AuthenticationWithUser from celery_compare.tasks import compare class CustomDate(fields.Date): def _deserialize(self, value, attr, data, **kwargs): return value class CustomDecimal(fields.Decimal): def _deserialize(self, value, attr, data, **kwargs): 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 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)), '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) } 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=16)), '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), '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)), '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)), '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))} 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=True), 'coApplicantName': fields.Str(required=True), 'guarantor1Name': fields.Str(required=True), 'guarantor2Name': fields.Str(required=True), } 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)), } doc_upload_args = { 'applicationData': fields.Nested(application_data_args, required=True), 'applicantData': fields.Nested(applicant_data_args, required=True), '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), } 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)), } upload_pdf_args = { 'pdf_file': fields.Raw(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) } 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)), } 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): 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') document_scheme = document.get('documentScheme') data_source = document.get('dataSource') document_name = document.get('documentName') # main_name = self.get_name(applicant_data, 'mainApplicantName', 16) # co_name = self.get_name(applicant_data, 'coApplicantName', 16) # g1_name = self.get_name(applicant_data, 'guarantor1Name', 16) # g2_name = self.get_name(applicant_data, 'guarantor2Name', 16) # try: # # 1. 上传信息记录 # UploadDocRecords.objects.create( # metadata_version_id=document.get('metadataVersionId'), # application_id=application_id, # main_applicant=main_name, # co_applicant=co_name, # guarantor_1=g1_name, # guarantor_2=g2_name, # document_name=document_name, # document_scheme=document_scheme, # business_type=business_type, # data_source=data_source, # upload_finish_time=document.get('uploadFinishTime'), # ) # except IntegrityError as e: # self.running_log.info('[doc upload fail] [args={0}] [err={1}]'.format(args, e)) # self.invalid_params(msg='metadataVersionId repeat') # else: data_source = self.fix_data_source(data_source) if data_source == consts.DATA_SOURCE_LIST[1]: if isinstance(document_name, str): if document_name.endswith('-证书.pdf') or document_name.endswith('-证书'): self.running_log.info('[doc upload success] [eapp license 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, # main_applicant=applicant_data.get('mainApplicantName'), # co_applicant=applicant_data.get('coApplicantName'), # guarantor_1=applicant_data.get('guarantor1Name'), # guarantor_2=applicant_data.get('guarantor2Name'), document_name=document.get('documentName'), document_scheme=self.fix_scheme(document_scheme), data_source=self.fix_data_source(data_source), upload_finish_time=document.get('uploadFinishTime'), ) # 3. 选择队列进入 is_priority = PriorityApplication.objects.filter(application_id=application_id, on_off=True).exists() tasks = ['{0}{1}{2}'.format(prefix, consts.SPLIT_STR, doc.id)] enqueue_res = rh.enqueue(tasks, is_priority) self.running_log.info('[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)) 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): 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) self.running_log.info('[priority doc success] [args={0}] [tasks_list={1}] [enqueue_res={2}]'.format( args, tasks_list, enqueue_res)) 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): # 存库 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') 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' ''' class SECompareView(GenericView): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # pos上传比对信息接口 SE @use_args(se_compare_args, location='data') def post(self, request, args): # 存库 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')) vehicle_info = json.dumps(content.get('vehicleInfo')) insurance_info = json.dumps(content.get('insuranceInfo')) bank_info = json.dumps(content.get('bankInfo')) quotationt_info = json.dumps(content.get('quotationtInfo')) corporate_cus_info = json.dumps(content.get('corporateCusInfo')) if isinstance( content.get('corporateCusInfo'), dict) else None comparison_class = HILSEComparisonInfo if business_type in consts.HIL_SET else AFCSEComparisonInfo comparison_class.objects.create( uniq_seq=uniq_seq, application_id=application_id, application_version=content.get('applicationVersion'), customer_type=content.get('customerType'), first_submmison_date=content.get('firstSubmmisonDate'), property_doc_policy=content.get('propertyDocumentPolicy', None), individual_cus_info=individual_cus_info, corporate_cus_info=corporate_cus_info, vehicle_info=vehicle_info, insurance_info=insurance_info, bank_info=bank_info, quotationt_info=quotationt_info ) # 触发比对 compare.apply_async((application_id, business_type, uniq_seq, None, False, False), queue='queue_compare') return response.ok() 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(GenericView, 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', 'data_source', 'status') 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) # total = len(doc_list) pagination = {'current': page, 'total': total, 'page_size': page_size} res = { 'pagination': pagination, 'doc_list': doc_list } 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, location='files') def post(self, request, args): random_int = random.randint(0, consts.TIME_NUM) metadata_version_id = str(int(time.time()) - random_int) pdf_file = args.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 = random.choice(consts.BUSINESS_TYPE_LIST) 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') 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) 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='', 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 tasks = ['{0}{1}{2}'.format(prefix, consts.SPLIT_STR, doc.id)] enqueue_res = rh.enqueue(tasks, 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') 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 result_obj.comments is None: comments = '' else: comments = result_obj.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': '' if result_obj is None else result_obj.update_time.strftime('%Y-%m-%d %H:%M'), 'source': '' if result_obj is None else result_obj.version.split(consts.SPLIT_STR)[0], 'version': '' if result_obj is None else result_obj.version.split(consts.SPLIT_STR)[1], '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 comments = '' if result_obj.comments is None else result_obj.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': '' if result_obj is None else result_obj.update_time.strftime('%Y-%m-%d %H:%M'), 'source': '' if result_obj is None else result_obj.version.split(consts.SPLIT_STR)[0], 'version': '' if result_obj is None else result_obj.version.split(consts.SPLIT_STR)[1], 'comments': comments, 'result': [] if result_obj is None else 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() error_type = [{'label': v, 'value': k} for k, v in error_type_map.items()] resources = { 'error_type': error_type } return response.ok(data=resources) class SECMSView(GenericView): permission_classes = [IsAuthenticated] authentication_classes = [OAuth2AuthenticationWithUser] # pos上传比对信息接口 SE # @use_args(se_cms_args, location='data') def post(self, request): 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('-')] 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, ) # 触发比对 compare.apply_async((application_id, business_type, None, None, False, True), queue='queue_compare') 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' '''