e5726dfc by 周伟奇

comparison part

1 parent 80b6584c
...@@ -1003,3 +1003,4 @@ APPLICANT_TYPE = ['COAPP', 'CUSTR', 'GAUTR1', 'GAUTR2'] ...@@ -1003,3 +1003,4 @@ APPLICANT_TYPE = ['COAPP', 'CUSTR', 'GAUTR1', 'GAUTR2']
1003 ID_TYPE = ['ITARI', 'ITHKM', 'ITPRC', 'ITPSP', 'ITRES', 'ITTID', 'ITUSC', 'ITCCU'] 1003 ID_TYPE = ['ITARI', 'ITHKM', 'ITPRC', 'ITPSP', 'ITRES', 'ITTID', 'ITUSC', 'ITCCU']
1004 SECOND_ID_TYPE = ['ITARI', 'ITHKM', 'ITPRC', 'ITPSP', 'ITRES', 'ITTID'] 1004 SECOND_ID_TYPE = ['ITARI', 'ITHKM', 'ITPRC', 'ITPSP', 'ITRES', 'ITTID']
1005 SUB_TYPE = ['CSIBM', 'CSOTH', 'CSSME'] 1005 SUB_TYPE = ['CSIBM', 'CSOTH', 'CSSME']
1006
......
1 PAGE_DEFAULT = 1
2 PAGE_SIZE_DEFAULT = 10
3
4 FIXED_APPLICATION_ID_PREFIX = 'CH-S'
5
6 DOC_SCHEME_LIST = ['ACCEPTANCE', 'SETTLEMENT', 'CONTRACT MANAGEMENT']
7 DATA_SOURCE_LIST = ['POS', 'EAPP', 'ECONTRACT']
8
9 HIL_PREFIX = 'HIL'
10 AFC_PREFIX = 'AFC'
11 SPLIT_STR = '_'
12 BUSINESS_TYPE_LIST = [HIL_PREFIX, AFC_PREFIX]
13 HIL_SET = {'HIL', 'HIl', 'HiL', 'Hil', 'hIL', 'hIl', 'hiL', 'hil', 'CO00002'}
14
15 # -------EDMS相关---------------------------------------------------------------------------------------------------
16
17 SESSION_PREFIX = 'FHLSID'
18 CUSTOM_CLIENT = 'CustomClient'
19 FIXED_TOKEN = '00000000-0000-0000-0000-000000000000'
20 FIXED_FILE_SIZE = 0
21 DOWNLOAD_ACTION_TYPE = 'Downloaded'
22
23 DOC_SCHEMA_ID_FILL = {
24 'ACCEPTANCE': (1, 'DFE-AutoFilingScript'),
25 'SETTLEMENT': (20, 'DFE-AutoFilingScript'),
26 'CONTRACT MANAGEMENT': (86, 'Schema-Based')
27 }
28 BUSINESS_TYPE_DICT = {
29 HIL_PREFIX: 'CO00002',
30 AFC_PREFIX: 'CO00001'
31 }
32 DOC_SCHEMA_TYPE = 'ElectronicRecord'
33 APPLICATION_ID_META_FIELD_id = 1
34 DEALER_CODE_META_FIELD_id = 13
35 BUSINESS_TYPE_META_FIELD_id = 93
36 DEALER_CODE = 'ocr_situ_group'
37
38 RETRY_TIMES = 3
39
40 # ---------银行流水模板相关--------------------------------------------------------------------------------------------
41
42 TRANS_MAP = {
43 'C': "0",
44 'c': "0",
45 '(': "0",
46 'o': "0",
47 'O': "0",
48 'D': "0",
49
50 '[': "1",
51 ']': "1",
52 'l': "1",
53 'L': "1",
54
55 'A': "4",
56
57 's': "5",
58 'S': "5",
59
60 'b': "6",
61
62 'g': "9",
63 'E': "9",
64
65 'B': "13",
66 }
67 TRANS = str.maketrans(TRANS_MAP)
68 ERROR_CHARS = {'.', '。', ':', ':', '•', '·', ',', ','}
69 SKIP_IMG_SHEET_NAME = '未处理图片'
70 SKIP_IMG_SHEET_HEADER = ('页码', '序号')
71
72 CARD_RATIO = 0.9
73 UNKNOWN_CARD = '未知卡号'
74 UNKNOWN_ROLE = '未知户名'
75 DATE_FORMAT = ['%Y年%m月%d日', '%Y/%m/%d', '%Y-%m-%d', '%Y%m%d']
76
77 PROOF_COL_TITLE = '核对结果'
78 PROOF_RES = ('对', '错')
79 META_SHEET_TITLE = '关键信息提取和展示'
80
81 FIXED_HEADERS = ('记账日期', '记账时间', '金额', '余额', '交易名称', '附言', '对方账户名', '对方卡号/账号',
82 '对方开户行', '核对结果', '借贷', '收入', '支出')
83 FIXED_COL_AMOUNT = len(FIXED_HEADERS)
84 BASE_HEADERS_MAPPING = {label: idx + 1 for idx, label in enumerate(FIXED_HEADERS)}
85 BORROW_HEADER_COL = BASE_HEADERS_MAPPING['借贷']
86 INCOME_HEADER_COL = BASE_HEADERS_MAPPING['收入']
87 OUTLAY_HEADER_COL = BASE_HEADERS_MAPPING['支出']
88 RESULT_HEADER_COL = BASE_HEADERS_MAPPING['核对结果']
89 BORROW_IDX = BORROW_HEADER_COL - 1
90 INCOME_IDX = INCOME_HEADER_COL - 1
91 OUTLAY_IDX = OUTLAY_HEADER_COL - 1
92 SUMMARY_IDX = FIXED_HEADERS.index('附言')
93 DATE_IDX = FIXED_HEADERS.index('记账日期')
94 AMOUNT_IDX = FIXED_HEADERS.index('金额')
95 OVER_IDX = FIXED_HEADERS.index('余额')
96 RESULT_IDX = FIXED_HEADERS.index('核对结果')
97 # '借贷': ('贷', '借'), # 竖版-无表格-广发银行
98 # '借贷状态': ('贷', '借'), # 竖版-特殊-交通银行
99 # '收/支': ('收入', '支出'), # 横版-表格-北京银行
100 BORROW_HEADERS_SET = {'借贷', '借贷状态', '收/支'}
101 BORROW_INCOME_SET = {'贷', '收入'}
102 BORROW_OUTLAY_SET = {'借', '支出'}
103 INCOME_HEADERS_SET = {'收入金额', '收入', '存入', '存入金额(贷)', '存入金额(贷)'}
104 OUTLAY_HEADERS_SET = {'支出金额', '支出', '支取金额(借)', '支取金额(借)'}
105
106 # ------------------普通打印-全格线--------------------------------------------------------------------------------------
107 HEADERS_MAPPING = {}
108 # 横版-表格-中国银行(不规则)
109 HEADERS_MAPPING.update(
110 {
111 '记账日期': BASE_HEADERS_MAPPING['记账日期'],
112 '记账时间': BASE_HEADERS_MAPPING['记账时间'],
113 '金额': BASE_HEADERS_MAPPING['金额'],
114 '余额': BASE_HEADERS_MAPPING['余额'],
115 '交易名称': BASE_HEADERS_MAPPING['交易名称'],
116 '附言': BASE_HEADERS_MAPPING['附言'],
117 '对方账户名': BASE_HEADERS_MAPPING['对方账户名'],
118 '对方卡号/账号': BASE_HEADERS_MAPPING['对方卡号/账号'],
119 '对方开户行': BASE_HEADERS_MAPPING['对方开户行'],
120 }
121 )
122 # 横版-表格-农业银行-中国农业银行个人账户明细
123 HEADERS_MAPPING.update(
124 {
125 '交易日期': BASE_HEADERS_MAPPING['记账日期'],
126 # '存入': BASE_HEADERS_MAPPING['金额'],
127 '对方账号': BASE_HEADERS_MAPPING['对方卡号/账号'],
128 '对方名称': BASE_HEADERS_MAPPING['对方账户名'],
129 '摘要': BASE_HEADERS_MAPPING['附言'],
130 }
131 )
132 # 横版-表格-北京银行
133 HEADERS_MAPPING.update(
134 {
135 '业务摘要': BASE_HEADERS_MAPPING['附言'],
136 '发生额': BASE_HEADERS_MAPPING['金额'],
137 '对方户名': BASE_HEADERS_MAPPING['对方账户名'],
138 }
139 )
140 # 横版-表格-工商银行 借记卡账户历史明细清单
141 # 横版-表格-工商银行-机打验证码 借记卡账户历史明细清单
142 # 横版-表格-工商银行CH-B008802400
143 # 横版-表格-工商银行 工资明细清单
144 # 工商银行历史明细(申请单号:20042501303039397888)
145 HEADERS_MAPPING.update(
146 {
147 '收入/支出金额': BASE_HEADERS_MAPPING['金额'],
148 '工作日期': BASE_HEADERS_MAPPING['记账日期'],
149 }
150 )
151
152 # 横版-表格-建设银行-个人活期账户交易明细
153 # 竖版-表格-建设银行-个人活期账户交易明细 CH-B005832604
154 # 竖版-表格-建设银行-工资账单CH-B008786812
155 # 竖版-表格-建设银行-个人活期账户交易明细 CH-B005832604 (2)
156 HEADERS_MAPPING.update(
157 {
158 '交易金额': BASE_HEADERS_MAPPING['金额'],
159 '账户余额': BASE_HEADERS_MAPPING['余额'],
160 '对方账号与户名': BASE_HEADERS_MAPPING['对方卡号/账号'],
161 }
162 )
163 # 微信
164 HEADERS_MAPPING.update(
165 {
166 '交易时间': BASE_HEADERS_MAPPING['记账时间'],
167 '交易类型': BASE_HEADERS_MAPPING['附言'],
168 '金额(元)': BASE_HEADERS_MAPPING['金额'],
169 '金额(元)': BASE_HEADERS_MAPPING['金额'],
170 '交易对方': BASE_HEADERS_MAPPING['对方账户名'],
171 }
172 )
173 # 支付宝
174 HEADERS_MAPPING.update(
175 {
176 '时间': BASE_HEADERS_MAPPING['记账日期'],
177 '名称/备注': BASE_HEADERS_MAPPING['附言'],
178 }
179 )
180
181 # ------------普通打印-部分格线-------------------------------------------------------------------------------------------
182
183 # 竖版-无表格-农业银行
184 # 竖版-无表格-农业银行CH-B008805428
185 HEADERS_MAPPING.update(
186 {
187 '摘要/附言': BASE_HEADERS_MAPPING['附言'],
188 '交易地点/对方账号和户名': BASE_HEADERS_MAPPING['对方卡号/账号'],
189 }
190 )
191 # 农业银行-窄页
192 HEADERS_MAPPING.update(
193 {
194 '交易对手账号': BASE_HEADERS_MAPPING['对方卡号/账号'],
195 }
196 )
197 # 竖版-特殊-农商行
198 HEADERS_MAPPING.update(
199 {
200 '交易发生额': BASE_HEADERS_MAPPING['金额'],
201 }
202 )
203 # 横版-特殊-中信银行-账户交易明细
204 HEADERS_MAPPING.update(
205 {
206 '对方银行': BASE_HEADERS_MAPPING['对方开户行'],
207 '交易摘要': BASE_HEADERS_MAPPING['附言'],
208 }
209 )
210 # 平安电子账单
211 HEADERS_MAPPING.update(
212 {
213 '借贷发生额(借:-贷:+)': BASE_HEADERS_MAPPING['金额'],
214 }
215 )
216
217 # ------------普通打印-无格线--------------------------------------------------------------------------------------------
218
219 # 竖版-无表格-招商银行(略歪)
220 # 竖版-无表格-招商银行账户历史交易明细表
221 HEADERS_MAPPING.update(
222 {
223 '联机余额': BASE_HEADERS_MAPPING['余额'],
224 }
225 )
226 # 竖版-无表格-邮储银行-账户对账单 含有对手方户名 对手方账户
227 # 竖版-无表格-邮储银行 账户对账单
228 # 竖版-无表格-邮储银行-电子章 邮储银行 账户对账单
229 HEADERS_MAPPING.update(
230 {
231 '交易金额(元)': BASE_HEADERS_MAPPING['金额'],
232 '交易金额(元)': BASE_HEADERS_MAPPING['金额'],
233 '账户余额(元)': BASE_HEADERS_MAPPING['余额'],
234 '账户余额(元)': BASE_HEADERS_MAPPING['余额'],
235 '对手方户名': BASE_HEADERS_MAPPING['对方账户名'],
236 '对手方账户': BASE_HEADERS_MAPPING['对方卡号/账号'],
237 }
238 )
239 # 横版-无表格-广发银行-账户交易历史 --> 已废弃
240 # 竖版-无表格-广发银行-账户交易历史 --> 已废弃
241 HEADERS_MAPPING.update(
242 {
243 '会计日期': BASE_HEADERS_MAPPING['记账日期'],
244 '对手户名': BASE_HEADERS_MAPPING['对方账户名'],
245 '对手账号': BASE_HEADERS_MAPPING['对方卡号/账号'],
246 }
247 )
248 # 招行电子账单 TODO 有英文,需测试
249 HEADERS_MAPPING.update(
250 {
251 '对手信息': BASE_HEADERS_MAPPING['对方账户名'],
252 '摘要代码': BASE_HEADERS_MAPPING['附言'],
253 }
254 )
255 # 横版-无表格-民生银行-中国民生银行个人账户对账单(客户卡号)
256 # 横版-无表格-民生银行-无标题(客户账户)
257 # 横版-无表格-民生银行
258 HEADERS_MAPPING.update(
259 {
260 '摘要信息': BASE_HEADERS_MAPPING['附言'],
261 '对方行名': BASE_HEADERS_MAPPING['对方开户行'],
262 }
263 )
264 # 竖版-无表格-农业银行整数
265 # 竖版-无表格-农业银行-中国农业银行银行卡交易明细清单
266 HEADERS_MAPPING.update(
267 {
268 '对方账号和户名': BASE_HEADERS_MAPPING['对方卡号/账号'],
269 }
270 )
271 # 竖版-无表格-农业银行-中国农业银行银行卡活期存折交易明细清单.pdf
272 # 竖版-无表格-农业银行-扩张.pdf
273 # 竖版-无表格-农业银行-缩进.pdf
274 HEADERS_MAPPING.update(
275 {
276 '日期': BASE_HEADERS_MAPPING['记账日期'],
277 '短摘要': BASE_HEADERS_MAPPING['附言'],
278 '本次余额': BASE_HEADERS_MAPPING['余额'],
279 }
280 )
281 # 竖版-无表格-农业银行-无标题(对手帐号)
282 HEADERS_MAPPING.update(
283 {
284 '交易后余额': BASE_HEADERS_MAPPING['余额'],
285 '对手帐号': BASE_HEADERS_MAPPING['对方卡号/账号'],
286 }
287 )
288 # 竖版-无表格-农商行(非常规)
289 HEADERS_MAPPING.update(
290 {
291 '交易说明': BASE_HEADERS_MAPPING['附言'],
292 }
293 )
294 # 竖版-无表格-工商银行 抬头三行 活期历史明细清单
295 HEADERS_MAPPING.update(
296 {
297 '对方账户': BASE_HEADERS_MAPPING['对方卡号/账号'],
298 }
299 )
300
301 # -----------针式打印-全格线--------------------------------------------------------------------------------------------
302 # 竖版-表格-建设银行-中国建设银行活期账户交易明细
303 # 竖版-表格-建设银行-中国建设银行活期账户明细清单
304 # 竖版-表格-建设银行-对私活期账户明细- (1).pdf
305 HEADERS_MAPPING.update(
306 {
307 '帐户余额': BASE_HEADERS_MAPPING['余额'],
308 '对方帐户名称': BASE_HEADERS_MAPPING['对方账户名'],
309 }
310 )
311 # 竖版-特殊-交通银行 零售客户交易清单 5000以上交易记录
312 HEADERS_MAPPING.update(
313 {
314 '交易日期 记账日期': BASE_HEADERS_MAPPING['记账日期'],
315 }
316 )
317
318 # ----------针式打印-部分格线------------------------------------------------------------------------------------------
319 # 竖版-特殊-邮储银行-一本通绿卡通交易明细(客户)
320 # 竖版-特殊-邮储银行-账户交易明细(客户)
321 HEADERS_MAPPING.update(
322 {
323 '对方账号/卡号/汇票号': BASE_HEADERS_MAPPING['对方卡号/账号'],
324 }
325 )
326
327 # --------------------------------------------------------------------------------------------------------------------
328
329 # ('记账日期', '记账时间', '金额', '余额', '交易名称', '附言', '对方账户名', '对方卡号/账号', '对方开户行', '核对结果', '借贷', '收入', '支出')
330 # CLASSIFY_LIST = [
331 # # --------------普通打印:全格线---------------------------------
332 # # 中国银行:记账日期 记账时间 币别 金额 余额 交易名称 渠道 网点名称 附言 对方账户名 对方卡号/账号 对方开户行
333 # ('中国银行', (1, 2, 4, 5, 6, 9, 10, 11, 12, None, None, None, None)), # 横版-表格-中国银行(不规则)
334 #
335 # # 农业银行:交易日期 交易网点 存入 支出 余额 对方账号 对方名称 摘要 渠道 附言
336 # ('农业银行-10', (1, None, None, 5, None, 8, 7, 6, None, None, None, 3, 4)), # 横版-表格-农业银行-中国农业银行个人账户明细
337 #
338 # # 农业银行:序号 日期 摘要 交易金额 余额 对方账号 对方名称 交易地点 渠道 附言
339 # ('农业银行-10-1', (2, None, 4, 5, None, 3, 7, 6, None, None, None, None, None)),
340 #
341 # # 农业银行:交易日期 摘要 交易金额 余额 交易渠道 交易网点 对方账号 对方名称 附言
342 # ('农业银行-9', (1, None, 3, 4, None, 2, 8, 7, None, None, None, None, None)),
343 #
344 # # 北京银行:交易日期 业务摘要 收/支 发生额 余额 对方户名 对方账号 交易渠道
345 # ('北京银行', (1, None, 4, 5, None, 2, 6, 7, None, None, 3, None, None)), # 横版-表格-北京银行
346 #
347 # # 工商银行:交易日期 账号 储种 序号 币种 钞汇 摘要 地区 收入/支出金额 余额 渠道
348 # ('工商银行', (1, None, 9, 10, None, 7, None, None, None, None, None, None, None)),
349 #
350 # # 工商银行:交易日期 账号 储种 序号 币种 钞汇 摘要 地区 收入/支出金额 余额 对方户名 对方账号 渠道
351 # ('工商银行-电子账单', (1, None, 9, 10, None, 7, 11, 12, None, None, None, None, None)),
352 #
353 # # 建设银行:空 摘要 交易日期 交易金额 账户余额 商户/网点号及其名称 对方账号与户名 --> 竖版-表格-建设银行
354 # # 序号 摘要 币别 钞汇 交易日期 交易金额 账户余额 交易地点附言 对方账号与户名 --> 横版-表格-建设银行
355 # ('建设银行-竖版', (3, None, 4, 5, None, 2, None, 7, None, None, None, None, None)),
356 # ('建设银行-横版', (5, None, 6, 7, None, 2, None, 9, None, None, None, None, None)),
357 #
358 # # 微信:交易单号 交易时间 交易类型 收/支/其他 交易方式 金额(元) 交易对方 商户单号
359 # ('微信', (2, None, 6, None, None, 3, 7, None, None, None, None, None, None)),
360 #
361 # # 支付宝:流水号 时间 名称/备注 收入 支出 账户余额 资金渠道
362 # ('支付宝', (2, None, None, 6, None, 3, None, None, None, None, None, 4, 5)),
363 #
364 # # -----------------普通打印:部分格线--------------------------------
365 #
366 # # 农业银行:交易日期 摘要/附言 交易金额 余额 交易地点/对方账号和户名
367 # ('农业银行-5', (1, None, 3, 4, None, 2, None, 5, None, None, None, None, None)),
368 #
369 # # 农业银行:日期 地点 摘要 存入 支出 余额 对方账号 对方户名
370 # ('农业银行-8', (1, None, None, 6, None, 3, 8, 7, None, None, None, 4, 5)),
371
372 # # 农业银行:日期 摘要 交易金额 余额 地点 交易对手账号 对方户名
373 # ('农业银行-窄页', (1, None, 3, 4, None, 2, 7, 6, None, None, None, None, None)),
374 #
375 # # 农商行:交易日期 交易发生额 账户余额 对方账号 对方户名 摘要 备注
376 # ('农商行', (1, None, 2, 3, None, 6, 5, 4, None, None, None, None, None)),
377 #
378 # # 中信银行:交易日期 交易摘要 收入金额 支出金额 账户余额 对方户名 对方账号 对方银行 交易流水号
379 # ('中信银行', (1, None, None, 5, None, 2, 6, 7, 8, None, None, 3, 4)),
380 #
381 # # 平安电子账单:序号 交易日期 交易网点 摘要 借贷发生额(借:-贷:+) 账户余额
382 # ('平安电子账单', (2, None, 5, 6, None, 4, None, None, None, None, None, None, None)),
383
384 # # 建设银行:序号 摘要 币别 钞汇 交易日期 交易金额 账户余额 交易地点附言 对方账号与户名
385 # ('建设银行-电子账单', (5, None, 6, 7, None, 2, None, 9, None, None, None, None, None)),
386 #
387 # # -----------------普通打印:无格线-------------------------------------
388 #
389 # # 招商银行:记账日期 货币 交易金额 联机余额 冲补账 交易摘要
390 # ('招商银行', (1, None, 3, 4, None, 6, None, None, None, None, None, None, None)),
391 #
392 # # 邮储银行:交易日期、交易类型 交易币种 交易金额(元) 账户余额(元) [对手方户名 对手方账户 收支类型] --> 竖版-无表格-邮储银行-账户对账单 含有对手方户名 对手方账户
393 # # 交易日期、交易类型 交易金额(元) 账户余额(元) 操作柜员 --> 竖版-无表格-邮储银行 账户对账单
394 # ('邮储银行-8', (1, None, 4, 5, None, 2, 6, 7, None, None, None, None, None)),
395 # ('邮储银行-5', (1, None, 3, 4, None, 2, None, None, None, None, None, None, None)),
396 #
397 # # 工商银行电子版:交易日期 账号 储种 序号 币种 妙汇 摘要 地区 收入/支出金额 余额 [对方户名 对方账号] 渠道
398 # ('工商银行电子版', (1, None, 9, 10, None, 7, None, None, None, None, None, None, None)),
399 #
400 # # 招商银行电子版:记账日期 货币 交易金额 联机余额 交易摘要 对手信息
401 # ('招商银行电子版', (1, None, 3, 4, None, 5, 6, None, None, None, None, None, None)),
402 #
403 # # 民生银行:凭证类型 凭证号码 摘要信息 交易时间 交易金额 账户余额 现转标志 交易渠道 交易机构 对方户名 对方行名 --> 横版-无表格-民生银行-中国民生银行个人账户对账单(客户卡号)
404 # # 凭证类型 凭证号码 交易时间 摘要 交易金额 账户余额 现转标志 交易渠道 交易机构 对方户名 对方行名 --> 横版-无表格-民生银行
405 # ('民生银行', (None, None, 5, 6, None, None, 7, None, 8, None, None, None, None)),
406 #
407 # # 农业银行:交易日期 摘要/附言 交易金额 对方账号和户名
408 # ('农业银行-整数', (1, None, 3, None, None, 2, None, 4, None, None, None, None, None)),
409 #
410 # # 农业银行:交易日期 摘要/附言 交易金额 余额 交易地点/对方账号和户名
411 # ('农业银行', (1, None, 3, 4, None, 2, None, 5, None, None, None, None, None)),
412 #
413 # # 农业银行:日期、时间、短摘要、交易金额、本次余额、交易网点、渠道、附言
414 # # 农业银行:日期、时间、日志号、短摘要、交易金额、本次余额、交易网点、渠道、附言
415 # ('农业银行', (1, 2, 4, 5, None, 3, None, None, None, None, None, None, None)),
416 # ('农业银行-扩张缩进', (1, 2, 5, 6, None, 4, None, None, None, None, None, None, None)),
417 #
418 # # 交通银行:交易日期 记账日期、交易地点、交易类型、借贷状态、交易金额、余额
419 # ('交通银行', (1, None, 5, 6, None, 3, None, None, None, None, 4, None, None)),
420 #
421 #
422 # # ================针式打印:有格线===================
423 #
424 # # 建设银行: 摘要、交易日期、交易金额、账户余额、商户/网点号及其名称、对方账号、对方户名 --> 竖版-表格-建设银行-中国建设银行活期账户明细清单
425 # # 交易日期、摘要、 币种、 钞汇、 交易金额、 帐户余额、对方账号、 对方帐户名称 --> 竖版-表格-建设银行-对私活期账户明细- (1)
426 # ('建设银行', (None, None, None, None, None, None, None, None, None, None, None, None, None)),
427 #
428 #
429 # # ================针式打印:无格线===================
430 #
431 # # 邮储银行:序号、交易日期、交易渠道、摘要、交易金额、账户余额、对方账号/卡号/汇票号、原子账号、交易机构名称
432 # ('邮储银行', (2, None, 5, 6, None, 4, None, 7, None, None, None, None, None)),
433 # ]
434
435 OTHER_TUPLE = (None, None, None, None, None, None, None, None, None, None, None, None, None)
436
437 # {
438 # "0":"其他",
439 # "1":"普通打印-全表格-中国农业银行",
440 # "2":"普通打印-全表格-中国银行",
441 # "3":"普通打印-全表格-北京银行",
442 # "4":"普通打印-全表格-工商银行",
443 # "5":"普通打印-全表格-建设银行",
444 # "6":"普通打印-全表格-微信账单",
445 # "7":"普通打印-全表格-支付宝账单",
446 # "8":"普通打印-无格线-中国邮政储蓄银行",
447
448 # "9":"普通打印-无格线-交通银行",
449 # "10":"普通打印-无格线-农业银行整数",
450 # "11":"普通打印-无格线-农业银行银行活期扩张缩进",
451 # "12":"普通打印-无格线-招商银行",
452 # "13":"普通打印-无格线-招行电子账单",
453 # "14":"普通打印-无格线-民生银行",
454
455 # "15":"普通打印-部分格线-横版-中信银行",
456 # "16":"普通打印-部分格线-竖版-中国农业银行分账户窄页",
457 # "17":"普通打印-部分格线-竖版-农业银行",
458 # "18":"普通打印-部分格线-竖版-农业银行银行卡交易明细",
459 # "19":"普通打印-部分格线-竖版-平安电子账单",
460
461 # "20":"针式打印-全格线-建设银行",
462 # "21":"针式打印-部分格线-竖版-邮储银行账户交易",
463 # "22":"针式打印-部分格线-邮储银行一本通绿卡"
464 # }
465
466 # CLASSIFY_LIST = [
467 # ('其他', OTHER_TUPLE),
468 # ('农业银行', (1, None, 3, 5, None, 8, 7, 6, None, None, None, None, None)),
469 # ('中国银行', (1, 2, 4, 5, 6, 9, 10, 11, 12, None, None, None, None)),
470 # ('北京银行', (1, None, 4, 5, None, 2, 6, 7, None, None, 3, None, None)),
471 # ('工商银行', (1, None, 9, 10, None, 7, None, None, None, None, None, None, None)),
472 # ('建设银行', (None, None, None, None, None, 2, None, None, None, None, None, None, None)),
473 # ('微信', (2, None, 6, None, None, 3, 7, None, None, None, None, None, None)),
474 # ('支付宝', (2, None, None, 6, None, 3, None, None, None, None, None, 4, 5)),
475 #
476 # ('交通银行', (1, None, 5, 6, None, 3, None, None, None, None, 4, None, None)),
477 # ('农业银行', (1, None, 3, None, None, 2, None, 4, None, None, None, None, None)),
478 # ('农业银行', (1, 2, None, None, None, None, None, None, None, None, None, None, None)),
479 # ('招商银行', (1, None, 3, 4, None, 6, None, None, None, None, None, None, None)),
480 # ('招商银行电子版', (1, None, 3, 4, None, 5, 6, None, None, None, None, None, None)),
481 # ('民生银行', (None, None, 5, 6, None, None, 7, None, 8, None, None, None, None)),
482 #
483 # ('中信银行', (1, None, None, 5, None, 2, 6, 7, 8, None, None, 3, 4)),
484 # ('农业银行', (1, None, 3, 4, None, 2, None, 5, None, None, None, None, None)),
485 # ('农业银行', (1, None, 3, 4, None, 2, None, 5, None, None, None, None, None)),
486 # ('农业银行', (1, None, 3, 4, None, 2, None, 5, None, None, None, None, None)),
487 # ('平安电子账单', (2, None, 5, 6, None, 4, None, None, None, None, None, None, None)),
488 #
489 # ('建设银行', (None, None, None, None, None, None, None, None, None, None, None, None, None)),
490 # ('邮储银行', (2, None, 5, 6, None, 4, None, 7, None, None, None, None, None)),
491 # ('邮储银行', (2, None, 5, 6, None, 4, None, 7, None, None, None, None, None)),
492 # ]
493
494 # "4":"普通打印-全表格-中国银行",
495 # "5":"普通打印-全表格-农业银行-10列",
496 # "6":"普通打印-全表格-农业银行-10列-1",
497 # "7":"普通打印-全表格-农业银行-9列",
498 # "8":"普通打印-全表格-北京银行",
499 # "9":"普通打印-全表格-工商银行",
500 # "10":"普通打印-全表格-工商银行-电子账单",
501 # "11":"普通打印-全表格-建设银行",
502 # "12":"普通打印-全表格-微信账单",
503 # "13":"普通打印-全表格-支付宝账单",
504
505 # "14":"普通打印-无格线-交通银行",
506 # "15":"普通打印-无格线-储蓄银行-5列",
507 # "16":"普通打印-无格线-储蓄银行-8列",
508 # "17":"普通打印-无格线-农业银行-扩张缩进",
509 # "18":"普通打印-无格线-农业银行-整数",
510 # "19":"普通打印-无格线-招商银行",
511 # "20":"普通打印-无格线-招商银行-电子账单",
512 # "21":"普通打印-无格线-民生银行",
513
514 # "22":"普通打印-部分格线-横版-中信银行",
515 # "23":"普通打印-部分格线-竖版-农业银行-5列",
516 # "24":"普通打印-部分格线-竖版-农业银行-8列",
517 # "25":"普通打印-部分格线-竖版-农业银行-窄页",
518 # "26":"普通打印-部分格线-竖版-平安电子账单",
519 # "27":"普通打印-部分格线-竖版-建设银行-电子账单",
520
521 # "34":"针式打印-全格线-建设银行",
522 # "35":"针式打印-部分格线-竖版-邮储银行",
523 # "36":"针式打印-部分格线-竖版-邮储银行-绿卡",
524
525 CLASSIFY_LIST = [
526 ('其他', OTHER_TUPLE),
527 ('其他', OTHER_TUPLE),
528 ('其他', OTHER_TUPLE),
529 ('其他', OTHER_TUPLE),
530 ('普通打印-全表格-中国银行', (1, 2, 4, 5, 6, 9, 10, 11, 12, None, None, None, None)),
531 ('普通打印-全表格-农业银行-10列', (1, None, None, 5, None, 8, 7, 6, None, None, None, 3, 4)),
532 ('普通打印-全表格-农业银行-10列-1', (2, None, 4, 5, None, 3, 7, 6, None, None, None, None, None)),
533 ('普通打印-全表格-农业银行-9列', (1, None, 3, 4, None, 2, 8, 7, None, None, None, None, None)),
534 ('普通打印-全表格-北京银行', (1, None, 4, 5, None, 2, 6, 7, None, None, 3, None, None)),
535 ('普通打印-全表格-工商银行', (1, None, 9, 10, None, 7, None, None, None, None, None, None, None)),
536 ('普通打印-全表格-工商银行-电子账单', (1, None, 9, 10, None, 7, 11, 12, None, None, None, None, None)),
537 ('普通打印-全表格-建设银行', (3, None, 4, 5, None, 2, None, 7, None, None, None, None, None)),
538 ('普通打印-全表格-微信账单', (2, None, 6, None, None, 3, 7, None, None, None, None, None, None)),
539 ('普通打印-全表格-支付宝账单', (2, None, None, 6, None, 3, None, None, None, None, None, 4, 5)),
540
541 ('普通打印-无格线-交通银行', (1, None, 5, 6, None, 3, None, None, None, None, 4, None, None)),
542 ('普通打印-无格线-储蓄银行-5列', (1, None, 3, 4, None, 2, None, None, None, None, None, None, None)),
543 ('普通打印-无格线-储蓄银行-8列', (1, None, 4, 5, None, 2, 6, 7, None, None, None, None, None)),
544 ('普通打印-无格线-农业银行-扩张缩进', (1, 2, 5, 6, None, 4, None, None, None, None, None, None, None)),
545 ('普通打印-无格线-农业银行-整数', (1, None, 3, None, None, 2, None, 4, None, None, None, None, None)),
546 ('普通打印-无格线-招商银行', (1, None, 3, 4, None, 6, None, None, None, None, None, None, None)),
547 ('普通打印-无格线-招商银行-电子账单', (1, None, 3, 4, None, 5, 6, None, None, None, None, None, None)),
548 ('普通打印-无格线-民生银行', (None, None, 5, 6, None, None, 7, None, 8, None, None, None, None)),
549
550 ('普通打印-部分格线-横版-中信银行', (1, None, None, 5, None, 2, 6, 7, 8, None, None, 3, 4)),
551 ('普通打印-部分格线-竖版-农业银行-5列', (1, None, 3, 4, None, 2, None, 5, None, None, None, None, None)),
552 ('普通打印-部分格线-竖版-农业银行-8列', (1, None, None, 6, None, 3, 8, 7, None, None, None, 4, 5)),
553 ('普通打印-部分格线-竖版-农业银行-窄页', (1, None, 3, 4, None, 2, 7, 6, None, None, None, None, None)),
554 ('普通打印-部分格线-竖版-平安电子账单', (2, None, 5, 6, None, 4, None, None, None, None, None, None, None)),
555 ('普通打印-部分格线-竖版-建设银行-电子账单', (5, None, 6, 7, None, 2, None, 9, None, None, None, None, None)),
556 ('其他', OTHER_TUPLE),
557 ('其他', OTHER_TUPLE),
558 ('其他', OTHER_TUPLE),
559 ('其他', OTHER_TUPLE),
560 ('其他', OTHER_TUPLE),
561 ('其他', OTHER_TUPLE),
562 ('针式打印-全格线-建设银行', OTHER_TUPLE),
563 ('针式打印-部分格线-竖版-邮储银行', (2, None, 5, 6, None, 4, None, 7, None, None, None, None, None)),
564 ('针式打印-部分格线-竖版-邮储银行-绿卡', (2, None, 5, 6, None, 4, None, 7, None, None, None, None, None)),
565 ('其他', OTHER_TUPLE),
566 ]
567
568 # ----------license相关------------------------------------------------------------------------------------------------
569
570 # "0":"AVT Invioce",
571 # "1":"二手车发票",
572 # "2":"其他",
573 # "3":"护照",
574 # "28":"机动车登记证",
575 # "29":"机动车销售统一发票",
576 # "30":"港澳通行证",
577 # "31":"营业执照",
578 # "32":"行驶证",
579 # "33":"身份证",
580 # "37":"银行卡"
581
582 # 其他
583 OTHER_CLASSIFY = 2
584
585 # 身份证
586 IC_CN_NAME = '身份证'
587 IC_CLASSIFY = 33
588 IC_FIELD_ORDER_0 = (('姓名', '姓名'),
589 ('公民身份号码', '公民身份号码'),
590 ('出生年月', '出生年月'),
591 ('住址', '住址'),
592 ('性别', '性别'),
593 ('民族', '民族'),)
594 IC_FIELD_ORDER_1 = (('有效期限', '有效期限'), ('签发机关', '签发机关'),)
595 # 居住证
596 RP_CN_NAME = '居住证'
597 RP_CLASSIFY = 10087
598 RP_FIELD_ORDER_0 = (('姓名', '姓名'),
599 ('公民身份号码', '公民身份号码'),
600 ('出生年月', '出生年月'),
601 ('住址', '住址'),
602 ('性别', '性别'),)
603 RP_FIELD_ORDER_1 = IC_FIELD_ORDER_1
604 # 增值税发票
605 VAT_CN_NAME = 'VAT普票'
606 VAT_CLASSIFY = 0
607 VAT_FIELD_ORDER = (('发票代码', '发票代码'),
608 ('发票代码(开具)', '发票代码(开具)'),
609 ('发票号码', '发票号码'),
610 ('发票号码(开具)', '发票号码(开具)'),
611 ('开票日期', '开票日期'),
612 ('校验码', '校验码'),
613 ('货物或应税劳务、服务名称', '货物或应税劳务、服务名称'),
614 ('金额合计', '开具金额合计(不含税)'),
615 ('税率', '税率'),
616 ('税额合计', '税额合计'),
617 ('价税合计小写', '价税合计(小写)'),
618 ('价税合计大写', '价税合计(大写)'),
619 ('购方名称', '购买方名称'),
620 ('购方纳税人识别号', '购买方纳税人识别号'),
621 ('购方地址、电话', '购买方地址、电话'),
622 ('购方开户行及账号', '购买方开户行及账号'),
623 ('销方名称', '销售方名称'),
624 ('销方纳税人识别号', '销售方纳税人识别号'),
625 ('销方地址、电话', '销售方地址、电话'),
626 ('销方开户行及账号', '销售方开户行及账号'),
627 ('销售方:(章)', '销售方:(章)'),
628 ('备注', '备注'),)
629 # 机动车登记证书
630 MVC_CN_NAME = '机动车登记证书'
631 MVC_CLASSIFY = 28
632 MVC_CLASSIFY_SE = 10086
633 MVC_FIELD_ORDER_1_2 = (('1.机动车所有人/身份证名称/号码', '机动车所有人/身份证明名称/号码'),
634 ('3.登记日期', '登记日期'),
635 ('9.车辆识别代号/车架号', '车辆识别代号/车架号'),
636 ('32.车辆出厂日期', '车辆出厂日期'),
637 ('34.发证日期', '发证日期'),
638 ('30.使用性质', '使用性质'),
639 ('31.车辆获得方式', '车辆获得方式'),
640 ('4.机动车登记编号', '机动车登记编号'),
641 ('空行占位', None),
642 ('5.车辆类型', '车辆类型'),
643 ('6.车辆品牌', '车辆品牌'),
644 ('7.车辆型号', '车辆型号'),
645 ('8.车身颜色', '车身颜色'),
646 ('10.国产/进口', '国产/进口'),
647 ('11.发动机号', '发动机号'),
648 ('12.发动机型号', '发动机型号'),
649 ('15.制造厂名称', '制造厂名称'),
650 ('2.登记机关', '登记机关'),
651 ('编号', '机动车登记证书编号'),)
652 MVC_FIELD_ORDER_3_4 = (
653 ('姓名/名称', '姓名/名称'),
654 ('身份证明名称/号码', '身份证明名称/号码'),
655 ('转移登记日期', '转移登记日期'),
656 )
657 MVC_SE_FIELD_ORDER_1_2 = (('9.车辆识别代号/车架号', '车辆识别代号/车架号'),
658 ('1.机动车所有人/身份证名称/号码', '机动车所有人/身份证明名称/号码'),
659 ('空行占位', None),
660 ('3.登记日期', '登记日期'),
661 ('32.车辆出厂日期', '车辆出厂日期'),
662 ('34.发证日期', '发证日期'),
663 ('30.使用性质', '使用性质'),
664 ('31.车辆获得方式', '车辆获得方式'),
665 ('5.车辆类型', '车辆类型'),
666 ('6.车辆品牌', '车辆品牌'),
667 ('7.车辆型号', '车辆型号'),
668 ('8.车身颜色', '车身颜色'),
669 ('10.国产/进口', '国产/进口'),
670 ('11.发动机号', '发动机号'),
671 ('12.发动机型号', '发动机型号'),
672 ('13.燃料种类', '燃料种类'),
673 ('14.排量/功率', '排量/功率'),
674 ('15.制造厂名称', '制造厂名称'),
675 ('16.转向形式', '转向形式'),
676 ('17.轮距', '轮距'),
677 ('18.轮胎数', '轮胎数'),
678 ('19.轮胎规格', '轮胎规格'),
679 ('20.钢板弹簧片数', '钢板弹簧片数'),
680 ('21.轴距', '轴距'),
681 ('22.轴数', '轴数'),
682 ('23.外廓尺寸', '外廓尺寸'),
683 ('24.货厢内部尺寸', '货厢内部尺寸'),
684 ('25.总质量', '总质量'),
685 ('26.核定载质量', '核定载质量'),
686 ('27.核定载客', '核定载客'),
687 ('28.准牵引总质量', '准牵引总质量'),
688 ('29.驾驶室载客', '驾驶室载客'),
689 ('2.登记机关', '登记机关'),
690 ('4.机动车登记编号', '机动车登记编号'),
691 ('编号', '机动车登记证书编号'),)
692 MVC_SE_FIELD_ORDER_3_4 = (
693 ('姓名/名称', '姓名/名称'),
694 ('身份证明名称/号码', '身份证明名称/号码'),
695 ('转移登记日期', '转移登记日期'),
696 )
697 # 机动车销售统一发票
698 MVI_CN_NAME = '机动车销售统一发票'
699 MVI_CLASSIFY = 29
700 MVI_FIELD_ORDER = (('发票代码', '发票代码'),
701 ('发票号码', '发票号码'),
702 ('开票日期', '开票日期'),
703 ('不含税价', '不含税价'),
704 ('发票类型', '发票联'),
705 ('购方名称', '购买方名称'),
706 ('购买方身份证号或组织机构代码', '购买方证件号码'),
707 ('纳税人识别号', '纳税人识别号'), # nodo
708 ('车辆识别代码', '车架号'),
709 ('价税合计小写', '价税合计小写'),
710 ('销方名称', '销货单位名称'),
711 ('增值税税额', '增值税税额'),
712 ('增值税税率', '增值税税率'), # nodo
713 ('发票章有无', '发票章有无'), # nodo 全国统一发票监制章 销售单位章
714 ('价税合计大写', '价税合计大写'), # nodo
715 ('', None),
716 ('发动机号码', '发动机号'),
717 ('车辆类型', '车辆类型'), # nodo
718 ('厂牌型号', '厂牌型号'), # nodo
719 ('产地', '产地'), # nodo
720 ('合格证号', '合格证号'), # nodo
721 ('进口证明书号', '进口证明书号'), # nodo
722 ('商检单号', '商检单号'), # nodo
723 ('电话', '电话'), # nodo
724 ('销方纳税人识别号', '销货方纳税人识别号'),
725 ('账号', '账号'), # nodo
726 ('地址', '地址'), # nodo
727 ('开户银行', '开户银行'), # nodo
728 ('主管税务机关及代码', '主管税务机关及代码'), # nodo
729 ('吨位', '吨位'), # nodo
730 ('限乘人数', '限乘人数'),) # nodo
731 IC_PID = VAT_PID = MVC_PID = MVI_PID = None
732
733 # 营业执照
734 BL_CN_NAME = '营业执照'
735 BL_CLASSIFY = 31
736 BL_PID = 41
737 BL_FIELD_ORDER = (('注册号', '统一社会信用代码'),
738 ('企业名称', '名称'),
739 ('企业类型', '类型'),
740 ('经营者姓名', '法定代表人'),
741 ('成立日期', '成立日期'),
742 ('营业期限', '营业期限'),
743 ('注册资本', '注册资本'),
744 ('地址', '住所'),
745 ('经营范围', '经营范围'),)
746 # 二手车发票
747 UCI_CN_NAME = '二手车发票'
748 UCI_CLASSIFY = 1
749 UCI_PID = 60
750 UCI_FIELD_ORDER = (('发票代码', '发票代码'),
751 ('发票号码', '发票号码'),
752 ('开票日期', '开票日期'),
753 ('车价合计', '车价合计小写'),
754 ('发票联', '发票联'),
755 ('购方单位', '买方单位/个人'),
756 ('购方号码', '买方单位代码/身份证号码'),
757 ('车架号码', '车架号'),
758 ('车价合计大写', '车价合计大写'),
759 ('二手车市场', '二手车市场'),
760 ('发票章有无', '发票章有无'),
761 ('空行占位', None),
762 ('车牌照号', '车牌照号'),
763 ('登记证号', '登记证号'),
764 ('购方地址', '买方单位/住址'),
765 ('车辆类型', '车辆类型'),
766 ('厂牌型号', '厂牌型号'),
767 ('车管所名称', '转入地车辆管理所名称'),
768 ('销方名称', '卖方单位/个人'),
769 ('销方号码', '卖方单位代码/身份证号码'),
770 ('销方地址', '卖方单位/个人住址'),)
771 # 港澳台通行证
772 EEP_CN_NAME = '港澳台通行证'
773 EEP_CLASSIFY = 30
774 EEP_PID = 1018
775 EEP_FIELD_ORDER = (('中文名', '姓名'), # 英文名
776 ('证件号码', '证件号码'),
777 ('签发次数', '换证次数(签发次数)'),
778 ('有效期限', '有效期限'),
779 ('出生日期', '出生日期'),
780 ('性别', '性别'),
781 ('签发机关', '签发机关'),
782 ('签发地点', '签发地点'),)
783 # 行驶证
784 DL_CN_NAME = '行驶证'
785 DL_CLASSIFY = 32
786 DL_PID = 5
787 DL_FIELD_ORDER_0 = (('号牌号码', '1 号牌号码'),
788 ('所有人', '3 所有人'),
789 ('使用性质', '5 使用性质'),
790 ('车辆识别代码', '7 车辆识别代号'),
791 ('注册日期', '9 注册日期'),
792 ('发证日期', '10 发证日期'),
793 ('车辆类型', '2 车辆类型'),
794 ('地址', '4 住址'),
795 ('品牌型号', '6 品牌型号'),
796 ('发动机号', '8 发动机号码'),)
797 DL_FIELD_ORDER_1 = (('号牌号码', '1 号牌号码'),
798 ('档案编号', '11 档案编号'),
799 ('核定载人数', '12 核定载人数'),
800 ('总质量', '13 总质量'),
801 ('整备质量', '14 整备质量'),
802 ('核定载质量', '15 核对载质量'),
803 ('外廓尺寸', '16 外廓尺寸'),
804 ('准牵引总质量', '17 准牵引总质量'),)
805 # 护照
806 PP_CN_NAME = '护照'
807 PP_CLASSIFY = 3
808 PP_PID = 8
809 PP_FIELD_ORDER = (('类型', '类型/Type'),
810 ('英文姓名', '姓名/Name'),
811 ('护照号码', '护照号码/Passport No'),
812 ('有效期至', '有效期至/Date of expiry'),
813 ('签发日期', '签发日期/Date of issue'),
814 ('国家码', '国家码/Country Code'),
815 ('性别', '性别/Sex'),
816 ('国籍', '国籍/Nationality'),
817 ('出生日期', '出生日期/Date of birth'),
818 ('出生地点', '出生地点/Place of birth'),
819 ('签发地点', '签发地点/Place of issue'),)
820 # 银行卡
821 BC_CN_NAME = '银行卡'
822 BC_CLASSIFY = 37
823 BC_PID = 4
824 # BC_FIELD = (('CardNum', '银行卡号'),
825 # ('BankName', '发卡行名称'),
826 # ('CardName', '银行卡名称'),
827 # ('BankCode', '发卡行代号'),
828 # ('CardType', '银行卡类型'),
829 # ('Date', '日期'))
830 BC_FIELD_ORDER = (('BankName', '发卡行名称'),
831 ('CardNum', '银行卡号'),
832 ('CardType', '银行卡类型'),)
833
834 SUCCESS_CODE_SET = {'0', 0}
835
836 FIELD_ORDER_MAP = {
837 IC_CLASSIFY: ('有效期限', IC_FIELD_ORDER_1, IC_FIELD_ORDER_0),
838 RP_CLASSIFY: ('有效期限', RP_FIELD_ORDER_1, RP_FIELD_ORDER_0),
839 DL_CLASSIFY: ('档案编号', DL_FIELD_ORDER_1, DL_FIELD_ORDER_0),
840 MVC_CLASSIFY: ('转移登记日期', MVC_FIELD_ORDER_3_4, MVC_FIELD_ORDER_1_2),
841 MVC_CLASSIFY_SE: ('转移登记日期', MVC_SE_FIELD_ORDER_3_4, MVC_SE_FIELD_ORDER_1_2)
842 }
843
844 LICENSE_ORDER = ((MVI_CLASSIFY, (MVI_PID, MVI_CN_NAME, MVI_FIELD_ORDER, False, False)),
845 (IC_CLASSIFY, (IC_PID, IC_CN_NAME, None, True, False)),
846 (RP_CLASSIFY, (None, RP_CN_NAME, None, True, False)),
847 (BC_CLASSIFY, (BC_PID, BC_CN_NAME, BC_FIELD_ORDER, False, False)),
848 (BL_CLASSIFY, (BL_PID, BL_CN_NAME, BL_FIELD_ORDER, False, False)),
849 (UCI_CLASSIFY, (UCI_PID, UCI_CN_NAME, UCI_FIELD_ORDER, False, False)),
850 (EEP_CLASSIFY, (EEP_PID, EEP_CN_NAME, EEP_FIELD_ORDER, False, False)),
851 (DL_CLASSIFY, (DL_PID, DL_CN_NAME, None, True, False)),
852 (PP_CLASSIFY, (PP_PID, PP_CN_NAME, PP_FIELD_ORDER, False, False)),
853 (MVC_CLASSIFY, (MVC_PID, MVC_CN_NAME, None, True, True)),
854 (VAT_CLASSIFY, (VAT_PID, VAT_CN_NAME, VAT_FIELD_ORDER, False, False)))
855
856 LICENSE_CLASSIFY_MAPPING = dict(LICENSE_ORDER)
857
858 OTHER_CLASSIFY_SET = {OTHER_CLASSIFY}
859 LICENSE_CLASSIFY_SET_1 = {IC_CLASSIFY, VAT_CLASSIFY, MVC_CLASSIFY, MVI_CLASSIFY}
860 LICENSE_CLASSIFY_SET_2 = {BL_CLASSIFY, UCI_CLASSIFY, EEP_CLASSIFY, DL_CLASSIFY, PP_CLASSIFY, BC_CLASSIFY}
...@@ -4,8 +4,6 @@ import json ...@@ -4,8 +4,6 @@ import json
4 import shutil 4 import shutil
5 import base64 5 import base64
6 import signal 6 import signal
7 import asyncio
8 import aiohttp
9 import difflib 7 import difflib
10 import requests 8 import requests
11 import traceback 9 import traceback
...@@ -24,8 +22,9 @@ from apps.doc import consts ...@@ -24,8 +22,9 @@ from apps.doc import consts
24 from apps.doc.ocr.edms import EDMS, rh 22 from apps.doc.ocr.edms import EDMS, rh
25 from apps.doc.named_enum import KeywordsType 23 from apps.doc.named_enum import KeywordsType
26 from apps.doc.exceptions import EDMSException, OCR1Exception, OCR2Exception, OCR4Exception 24 from apps.doc.exceptions import EDMSException, OCR1Exception, OCR2Exception, OCR4Exception
27 from apps.doc.ocr.wb import BSWorkbook, Workbook 25 from apps.doc.ocr.wb import BSWorkbook
28 from apps.doc.models import DocStatus, HILDoc, AFCDoc, Keywords 26 from apps.doc.models import DocStatus, HILDoc, AFCDoc, Keywords
27 from celery_compare.tasks import compare
29 28
30 29
31 class Command(BaseCommand, LoggerMixin): 30 class Command(BaseCommand, LoggerMixin):
...@@ -545,7 +544,7 @@ class Command(BaseCommand, LoggerMixin): ...@@ -545,7 +544,7 @@ class Command(BaseCommand, LoggerMixin):
545 self.cronjob_log.warn('{0} [process failed (pdf_2_img_2_queue)] [task={1}] ' 544 self.cronjob_log.warn('{0} [process failed (pdf_2_img_2_queue)] [task={1}] '
546 '[error={2}]'.format(self.log_base, task_str, traceback.format_exc())) 545 '[error={2}]'.format(self.log_base, task_str, traceback.format_exc()))
547 except Exception as e: 546 except Exception as e:
548 self.cronjob_log.error('{0} [process error (db save 1)] [error={1}]'.format( 547 self.cronjob_log.error('{0} [process error (db save)] [error={1}]'.format(
549 self.log_base, traceback.format_exc())) 548 self.log_base, traceback.format_exc()))
550 error_list.append(1) 549 error_list.append(1)
551 return 550 return
...@@ -595,27 +594,27 @@ class Command(BaseCommand, LoggerMixin): ...@@ -595,27 +594,27 @@ class Command(BaseCommand, LoggerMixin):
595 except Exception as e: 594 except Exception as e:
596 self.cronjob_log.error('{0} [process error (ocr fetch)] [img_path={1}] [error={2}]'.format( 595 self.cronjob_log.error('{0} [process error (ocr fetch)] [img_path={1}] [error={2}]'.format(
597 self.log_base, img_path, traceback.format_exc())) 596 self.log_base, img_path, traceback.format_exc()))
597 else:
598 try:
599 del json_data_1
600 # /data/bmw-ocr-data/AFC/tmp/6/img/page_0_img_0.jpeg
601 # AFC_2
602 path_split = img_path.split('/')
603 task_str = consts.SPLIT_STR.join((path_split[-5], path_split[-3]))
598 604
599 try: 605 with lock:
600 del json_data_1 606 doc_res_dict = res_dict.setdefault(task_str, {})
601 # /data/bmw-ocr-data/AFC/tmp/6/img/page_0_img_0.jpeg 607 doc_res_dict[img_path] = ocr_1_res
602 # AFC_2 608 res_dict[task_str] = doc_res_dict
603 path_split = img_path.split('/') 609 todo_count = todo_count_dict.get(task_str)
604 task_str = consts.SPLIT_STR.join((path_split[-5], path_split[-3])) 610 if todo_count == 1:
605 611 finish_queue.put(task_str)
606 with lock: 612 del todo_count_dict[task_str]
607 doc_res_dict = res_dict.setdefault(task_str, {}) 613 else:
608 doc_res_dict[img_path] = ocr_1_res 614 todo_count_dict[task_str] = todo_count - 1
609 res_dict[task_str] = doc_res_dict 615 except Exception as e:
610 todo_count = todo_count_dict.get(task_str) 616 self.cronjob_log.error('{0} [process error (store ocr res)] [img_path={1}] [error={2}]'.format(
611 if todo_count == 1: 617 self.log_base, img_path, traceback.format_exc()))
612 finish_queue.put(task_str)
613 del todo_count_dict[task_str]
614 else:
615 todo_count_dict[task_str] = todo_count - 1
616 except Exception as e:
617 self.cronjob_log.error('{0} [process error (store ocr res)] [img_path={1}] [error={2}]'.format(
618 self.log_base, img_path, traceback.format_exc()))
619 618
620 def res_2_wb(self, res_dict, img_queue, finish_queue, lock, error_list): 619 def res_2_wb(self, res_dict, img_queue, finish_queue, lock, error_list):
621 while len(error_list) == 0 or not img_queue.empty() or not finish_queue.empty(): 620 while len(error_list) == 0 or not img_queue.empty() or not finish_queue.empty():
...@@ -626,221 +625,220 @@ class Command(BaseCommand, LoggerMixin): ...@@ -626,221 +625,220 @@ class Command(BaseCommand, LoggerMixin):
626 time.sleep(self.sleep_time_task_get) 625 time.sleep(self.sleep_time_task_get)
627 continue 626 continue
628 else: 627 else:
628 self.cronjob_log.info('{0} [res_2_wb] [get task] [task={1}]'.format(self.log_base, task_str))
629 ocr_1_res = res_dict.pop(task_str, {})
630
631 business_type, doc_id_str = task_str.split(consts.SPLIT_STR)
632 doc_id = int(doc_id_str)
633 doc_class = HILDoc if business_type == consts.HIL_PREFIX else AFCDoc
634
635 doc_data_path = os.path.join(self.data_dir, business_type, consts.TMP_DIR_NAME, doc_id_str)
636 excel_path = os.path.join(doc_data_path, '{0}.xlsx'.format(doc_id_str))
637
629 try: 638 try:
630 self.cronjob_log.info('{0} [res_2_wb] [get task] [task={1}]'.format(self.log_base, task_str)) 639 doc = doc_class.objects.filter(id=doc_id).first()
631 ocr_1_res = res_dict.get(task_str, {}) 640 except Exception as e:
632 # self.cronjob_log.info('{0} [res_2_wb] [get task res] [task={1}]'.format( 641 self.cronjob_log.error('{0} [process error (db filter)] [task={1}] [error={2}]'.format(
633 # self.log_base, task_str)) 642 self.log_base, task_str, traceback.format_exc()))
634 643 else:
635 # 4.OCR结果并且构建excel文件 644 try:
636 bs_summary = {} 645 # 4.OCR结果并且构建excel文件
637 license_summary = {} 646 bs_summary = {}
638 unknown_summary = {} 647 unknown_summary = {}
639 res_list = [] 648 license_summary = {}
640 interest_keyword = Keywords.objects.filter( 649 res_list = []
641 type=KeywordsType.INTEREST.value, on_off=True).values_list('keyword', flat=True) 650 interest_keyword = Keywords.objects.filter(
642 salary_keyword = Keywords.objects.filter( 651 type=KeywordsType.INTEREST.value, on_off=True).values_list('keyword', flat=True)
643 type=KeywordsType.SALARY.value, on_off=True).values_list('keyword', flat=True) 652 salary_keyword = Keywords.objects.filter(
644 loan_keyword = Keywords.objects.filter( 653 type=KeywordsType.SALARY.value, on_off=True).values_list('keyword', flat=True)
645 type=KeywordsType.LOAN.value, on_off=True).values_list('keyword', flat=True) 654 loan_keyword = Keywords.objects.filter(
646 wechat_keyword = Keywords.objects.filter( 655 type=KeywordsType.LOAN.value, on_off=True).values_list('keyword', flat=True)
647 type=KeywordsType.ALI_WECHART.value, on_off=True).values_list('keyword', flat=True) 656 wechat_keyword = Keywords.objects.filter(
648 wb = BSWorkbook(interest_keyword, salary_keyword, loan_keyword, wechat_keyword) 657 type=KeywordsType.ALI_WECHART.value, on_off=True).values_list('keyword', flat=True)
649 for img_path, res in ocr_1_res.items(): 658 wb = BSWorkbook(interest_keyword, salary_keyword, loan_keyword, wechat_keyword)
650 pno, ino = self.parse_img_path(img_path) 659 for img_path, res in ocr_1_res.items():
651 part_idx = 1 660 pno, ino = self.parse_img_path(img_path)
652 if res.get('code') == 1: 661 part_idx = 1
653 ocr_data_list = res.get('data', []) 662 if res.get('code') == 1:
654 if not isinstance(ocr_data_list, list): 663 ocr_data_list = res.get('data', [])
655 res_list.append((pno, ino, part_idx, consts.RES_FAILED_3)) 664 if not isinstance(ocr_data_list, list):
656 self.cronjob_log.warn('{0} [ocr_1 res error] [img={1}]'.format(self.log_base, img_path)) 665 res_list.append((pno, ino, part_idx, consts.RES_FAILED_3))
657 else: 666 self.cronjob_log.warn('{0} [ocr_1 res error] [img={1}]'.format(self.log_base, img_path))
658 for part_idx, ocr_data in enumerate(ocr_data_list): 667 else:
659 part_idx = part_idx + 1 668 for part_idx, ocr_data in enumerate(ocr_data_list):
660 classify = ocr_data.get('classify') 669 part_idx = part_idx + 1
661 if classify is None: 670 classify = ocr_data.get('classify')
662 res_list.append((pno, ino, part_idx, consts.RES_FAILED_3)) 671 if classify is None:
663 self.cronjob_log.warn('{0} [ocr_1 res error] [img={1}]'.format( 672 res_list.append((pno, ino, part_idx, consts.RES_FAILED_3))
664 self.log_base, img_path)) 673 self.cronjob_log.warn('{0} [ocr_1 res error] [img={1}]'.format(
665 continue 674 self.log_base, img_path))
666 elif classify in consts.OTHER_CLASSIFY_SET: # 其他类 675 continue
667 res_list.append((pno, ino, part_idx, consts.RES_SUCCESS_OTHER)) 676 elif classify in consts.OTHER_CLASSIFY_SET: # 其他类
668 continue 677 res_list.append((pno, ino, part_idx, consts.RES_SUCCESS_OTHER))
669 elif classify in consts.LICENSE_CLASSIFY_SET_1: # 证件1 678 continue
670 self.license1_process(ocr_data, license_summary, classify, res_list, 679 elif classify in consts.LICENSE_CLASSIFY_SET_1: # 证件1
671 pno, ino, part_idx, img_path) 680 self.license1_process(ocr_data, license_summary, classify, res_list,
672 elif classify in consts.LICENSE_CLASSIFY_SET_2: # 证件2 681 pno, ino, part_idx, img_path)
673 pid, _, _, _, _, _ = consts.LICENSE_CLASSIFY_MAPPING.get(classify) 682 elif classify in consts.LICENSE_CLASSIFY_SET_2: # 证件2
674 file_data = ocr_data.get('section_img') 683 pid, _, _, _, _, _ = consts.LICENSE_CLASSIFY_MAPPING.get(classify)
675 if file_data is None: 684 file_data = ocr_data.get('section_img')
676 with open(img_path, 'rb') as f: 685 if file_data is None:
677 base64_data = base64.b64encode(f.read()) 686 with open(img_path, 'rb') as f:
678 # 获取解码后的base64值 687 base64_data = base64.b64encode(f.read())
679 file_data = base64_data.decode() 688 # 获取解码后的base64值
680 json_data_2 = { 689 file_data = base64_data.decode()
681 "pid": str(pid), 690 json_data_2 = {
682 "filedata": file_data 691 "pid": str(pid),
683 } 692 "filedata": file_data
684 693 }
685 for times in range(consts.RETRY_TIMES): 694
686 try: 695 for times in range(consts.RETRY_TIMES):
687 start_time = time.time() 696 try:
688 ocr_2_response = requests.post(self.ocr_url_2, data=json_data_2) 697 start_time = time.time()
689 if ocr_2_response.status_code != 200: 698 ocr_2_response = requests.post(self.ocr_url_2, data=json_data_2)
690 raise OCR2Exception('ocr_2 status code: {0}'.format(ocr_2_response.status_code)) 699 if ocr_2_response.status_code != 200:
691 except Exception as e: 700 raise OCR2Exception('ocr_2 status code: {0}'.format(ocr_2_response.status_code))
692 self.cronjob_log.warn( 701 except Exception as e:
693 '{0} [ocr_2 failed] [times={1}] [img_path={2}] [error={3}]'.format( 702 self.cronjob_log.warn(
694 self.log_base, times, img_path, traceback.format_exc())) 703 '{0} [ocr_2 failed] [times={1}] [img_path={2}] [error={3}]'.format(
704 self.log_base, times, img_path, traceback.format_exc()))
705 else:
706 ocr_2_res = json.loads(ocr_2_response.text)
707 end_time = time.time()
708 speed_time = int(end_time - start_time)
709 self.cronjob_log.info(
710 '{0} [ocr_2 success] [img={1}] [speed_time={2}]'.format(
711 self.log_base, img_path, speed_time))
712
713 if classify == consts.BC_CLASSIFY:
714 name = '有'
715 json_data_3 = {
716 "file": file_data,
717 'card_res': ocr_2_res
718 }
719 card_name_response = requests.post(self.ocr_url_3, json_data_3)
720 if card_name_response.status_code == 200:
721 card_name_res = card_name_response.json()
722 if isinstance(card_name_res, dict) and \
723 card_name_res.get('data', {}).get('is_exists_name') == 0:
724 name = '无'
725 ocr_2_res['Name'] = name
726 self.license2_process(ocr_2_res, license_summary, pid, classify, res_list, pno, ino, part_idx)
727 break
695 else: 728 else:
696 ocr_2_res = json.loads(ocr_2_response.text) 729 res_list.append((pno, ino, part_idx, consts.RES_FAILED_2))
697 end_time = time.time() 730 self.cronjob_log.warn(
698 speed_time = int(end_time - start_time) 731 '{0} [ocr_2 failed] [img_path={1}]'.format(self.log_base, img_path))
699 self.cronjob_log.info( 732 else: # 流水处理
700 '{0} [ocr_2 success] [img={1}] [speed_time={2}]'.format( 733 self.bs_process(wb, ocr_data, bs_summary, unknown_summary, classify, res_list, pno, ino, part_idx)
701 self.log_base, img_path, speed_time)) 734 else:
702 735 res_list.append((pno, ino, part_idx, consts.RES_FAILED_1))
703 if classify == consts.BC_CLASSIFY: 736 self.cronjob_log.info('{0} [ocr_1 res error] [img={1}]'.format(self.log_base, img_path))
704 name = '有'
705 json_data_3 = {
706 "file": file_data,
707 'card_res': ocr_2_res
708 }
709 card_name_response = requests.post(self.ocr_url_3, json_data_3)
710 if card_name_response.status_code == 200:
711 card_name_res = card_name_response.json()
712 if isinstance(card_name_res, dict) and \
713 card_name_res.get('data', {}).get('is_exists_name') == 0:
714 name = '无'
715 ocr_2_res['Name'] = name
716 self.license2_process(ocr_2_res, license_summary, pid, classify, res_list, pno, ino, part_idx)
717 break
718 else:
719 res_list.append((pno, ino, part_idx, consts.RES_FAILED_2))
720 self.cronjob_log.warn(
721 '{0} [ocr_2 failed] [img_path={1}]'.format(self.log_base, img_path))
722 else: # 流水处理
723 self.bs_process(wb, ocr_data, bs_summary, unknown_summary, classify, res_list, pno, ino, part_idx)
724 else:
725 res_list.append((pno, ino, part_idx, consts.RES_FAILED_1))
726 self.cronjob_log.info('{0} [ocr_1 res error] [img={1}]'.format(self.log_base, img_path))
727
728 with lock:
729 del res_dict[task_str]
730 # self.cronjob_log.info('{0} [res_dict record] [res_dict={1}]'.format(
731 # self.log_base, res_dict))
732 737
733 self.cronjob_log.info('{0} [task={1}] [bs_summary={2}] [unknown_summary={3}] ' 738 self.cronjob_log.info('{0} [task={1}] [bs_summary={2}] [unknown_summary={3}] '
734 '[license_summary={4}]'.format(self.log_base, task_str, bs_summary, 739 '[license_summary={4}]'.format(self.log_base, task_str, bs_summary,
735 unknown_summary, license_summary)) 740 unknown_summary, license_summary))
736 741
737 self.license_log.info('[task={0}] [license_summary={1}]'.format(task_str, license_summary)) 742 self.license_log.info('[task={0}] [license_summary={1}]'.format(task_str, license_summary))
738 idcard_list = license_summary.get(consts.IC_CLASSIFY) 743 idcard_list = license_summary.get(consts.IC_CLASSIFY)
739 if idcard_list: 744 if idcard_list:
740 self.idcard_log.info('[task={0}] [idcard={1}]'.format(task_str, idcard_list)) 745 self.idcard_log.info('[task={0}] [idcard={1}]'.format(task_str, idcard_list))
741 746
742 merged_bs_summary = self.rebuild_bs_summary(bs_summary, unknown_summary) 747 merged_bs_summary = self.rebuild_bs_summary(bs_summary, unknown_summary)
743 748
744 self.bs_log.info('[task={0}] [bs_summary={1}]'.format(task_str, merged_bs_summary)) 749 self.bs_log.info('[task={0}] [bs_summary={1}]'.format(task_str, merged_bs_summary))
745 750
746 self.cronjob_log.info('{0} [task={1}] [merged_bs_summary={2}] [unknown_summary={3}] ' 751 self.cronjob_log.info('{0} [task={1}] [merged_bs_summary={2}] [unknown_summary={3}] '
747 '[res_list={4}]'.format(self.log_base, task_str, merged_bs_summary, 752 '[res_list={4}]'.format(self.log_base, task_str, merged_bs_summary,
748 unknown_summary, res_list)) 753 unknown_summary, res_list))
749 del unknown_summary 754 del unknown_summary
750 755
751 # 4.2 重构Excel文件
752 # doc, business_type = self.get_doc_object(task_str)
753 business_type, doc_id_str = task_str.split(consts.SPLIT_STR)
754 doc_id = int(doc_id_str)
755 doc_class = HILDoc if business_type == consts.HIL_PREFIX else AFCDoc
756 doc = doc_class.objects.filter(id=doc_id).first()
757 doc_data_path = os.path.join(self.data_dir, business_type, consts.TMP_DIR_NAME, str(doc.id))
758 excel_path = os.path.join(doc_data_path, '{0}.xlsx'.format(doc.id))
759 # src_excel_path = os.path.join(doc_data_path, 'src.xlsx')
760 # wb.save(src_excel_path)
761 count_list = wb.rebuild(merged_bs_summary, license_summary, res_list, doc.document_scheme)
762 wb.save(excel_path)
763 except Exception as e:
764 try:
765 with lock:
766 if task_str in res_dict:
767 del res_dict[task_str]
768 # doc, business_type = self.get_doc_object(task_str)
769 business_type, doc_id_str = task_str.split(consts.SPLIT_STR)
770 doc_id = int(doc_id_str)
771 doc_class = HILDoc if business_type == consts.HIL_PREFIX else AFCDoc
772 doc = doc_class.objects.filter(id=doc_id).first()
773 doc.status = DocStatus.PROCESS_FAILED.value
774 doc.save()
775 self.cronjob_log.warn('{0} [process failed (res to wb)] [task={1}] [error={2}]'.format(
776 self.log_base, task_str, traceback.format_exc()))
777 except Exception as e: 756 except Exception as e:
778 self.cronjob_log.error('{0} [process error (wb end)] [task={1}] [error={2}]'.format(
779 self.log_base, task_str, traceback.format_exc()))
780 757
781 try: 758 self.cronjob_log.warn('{0} [process failed (res conformity)] [task={1}] [error={2}]'.format(
782 doc_data_path = os.path.join(self.data_dir, business_type, consts.TMP_DIR_NAME, str(doc.id))
783 img_save_path = os.path.join(doc_data_path, 'img')
784 shutil.rmtree(img_save_path, ignore_errors=True)
785 pdf_path = os.path.join(doc_data_path, '{0}.pdf'.format(doc.id))
786 os.remove(pdf_path)
787 except Exception as e:
788 self.cronjob_log.error('{0} [process error (file remove 1)] [task={1}] [error={2}]'.format(
789 self.log_base, task_str, traceback.format_exc())) 759 self.log_base, task_str, traceback.format_exc()))
790 else: 760
791 try:
792 img_save_path = os.path.join(doc_data_path, 'img')
793 write_zip_file(img_save_path, os.path.join(doc_data_path, '{0}_img.zip'.format(doc.id)))
794 shutil.rmtree(img_save_path, ignore_errors=True)
795 pdf_path = os.path.join(doc_data_path, '{0}.pdf'.format(doc.id))
796 os.remove(pdf_path)
797 # os.remove(src_excel_path)
798 except Exception as e:
799 self.cronjob_log.error('{0} [process error (file remove 2)] [task={1}] [error={2}]'.format(
800 self.log_base, task_str, traceback.format_exc()))
801 try:
802 # 5.上传至EDMS
803 for times in range(consts.RETRY_TIMES):
804 try:
805 self.edms.upload(excel_path, doc, business_type)
806 except Exception as e:
807 self.cronjob_log.warn(
808 '{0} [edms upload failed] [times={1}] [task={2}] [error={3}]'.format(
809 self.log_base, times, task_str, traceback.format_exc()))
810 edms_exc = str(e)
811 else:
812 break
813 else:
814 raise EDMSException(edms_exc)
815 except Exception as e:
816 try: 761 try:
817 doc.status = DocStatus.UPLOAD_FAILED.value 762 doc.status = DocStatus.PROCESS_FAILED.value
818 doc.end_time = timezone.now()
819 doc.duration = min((doc.end_time - doc.start_time).seconds, 32760)
820 for field, count in count_list:
821 if hasattr(doc, field):
822 setattr(doc, field, count)
823 doc.save() 763 doc.save()
824 self.cronjob_log.warn('{0} [process failed (edms upload)] [task={1}] [error={2}]'.format(
825 self.log_base, task_str, traceback.format_exc()))
826 except Exception as e: 764 except Exception as e:
827 self.cronjob_log.error('{0} [process error (edms upload)] [task={1}] [error={2}]'.format( 765 self.cronjob_log.error('{0} [process error (db save)] [task={1}] [error={2}]'.format(
828 self.log_base, task_str, traceback.format_exc())) 766 self.log_base, task_str, traceback.format_exc()))
767
829 else: 768 else:
769
830 try: 770 try:
831 doc.status = DocStatus.COMPLETE.value 771 # 重构Excel文件
832 doc.end_time = timezone.now() 772 # src_excel_path = os.path.join(doc_data_path, 'src.xlsx')
833 doc.duration = min((doc.end_time - doc.start_time).seconds, 32760) 773 # wb.save(src_excel_path)
834 for field, count in count_list: 774 count_list = wb.rebuild(merged_bs_summary, license_summary, res_list, doc.document_scheme)
835 if hasattr(doc, field): 775 wb.save(excel_path)
836 setattr(doc, field, count) 776
837 doc.save()
838 self.cronjob_log.info('{0} [process complete] [task={1}]'.format(self.log_base, task_str))
839 os.remove(excel_path)
840 except Exception as e: 777 except Exception as e:
841 self.cronjob_log.error('{0} [process error (completed)] [task={1}] [error={2}]'.format( 778
779 self.cronjob_log.warn('{0} [process failed (wb rebuild)] [task={1}] [error={2}]'.format(
842 self.log_base, task_str, traceback.format_exc())) 780 self.log_base, task_str, traceback.format_exc()))
843 781
782 try:
783 doc.status = DocStatus.PROCESS_FAILED.value
784 doc.save()
785 except Exception as e:
786 self.cronjob_log.error('{0} [process error (db save)] [task={1}] [error={2}]'.format(
787 self.log_base, task_str, traceback.format_exc()))
788
789 else:
790 try:
791 # 上传至EDMS
792 for times in range(consts.RETRY_TIMES):
793 try:
794 self.edms.upload(excel_path, doc, business_type)
795 except Exception as e:
796 self.cronjob_log.warn(
797 '{0} [edms upload failed] [times={1}] [task={2}] [error={3}]'.format(
798 self.log_base, times, task_str, traceback.format_exc()))
799 edms_exc = str(e)
800 else:
801 break
802 else:
803 raise EDMSException(edms_exc)
804 except Exception as e:
805 doc.status = DocStatus.UPLOAD_FAILED.value
806 self.cronjob_log.warn('{0} [process failed (edms upload)] [task={1}] [error={2}]'.format(
807 self.log_base, task_str, traceback.format_exc()))
808 else:
809 doc.status = DocStatus.COMPLETE.value
810 self.cronjob_log.info('{0} [edms upload success] [task={1}]'.format(self.log_base, task_str))
811 finally:
812 try:
813 doc.end_time = timezone.now()
814 doc.duration = min((doc.end_time - doc.start_time).seconds, 32760)
815 for field, count in count_list:
816 if hasattr(doc, field):
817 setattr(doc, field, count)
818 doc.save()
819 except Exception as e:
820 self.cronjob_log.error('{0} [process error (db save)] [task={1}] [error={2}]'.format(
821 self.log_base, task_str, traceback.format_exc()))
822 else:
823 self.cronjob_log.info('{0} [process complete] [task={1}]'.format(self.log_base, task_str))
824 os.remove(excel_path)
825 finally:
826 # TODO 识别结果存一张表,方便跑报表
827 # 更新OCR累计识别结果表
828
829 # 触发比对
830 compare.apply_async((doc.application_id, business_type, None, ocr_res_id), queue='queue_compare')
831 finally:
832 try:
833 img_save_path = os.path.join(doc_data_path, 'img')
834 write_zip_file(img_save_path, os.path.join(doc_data_path, '{0}_img.zip'.format(doc_id_str)))
835 shutil.rmtree(img_save_path, ignore_errors=True)
836 pdf_path = os.path.join(doc_data_path, '{0}.pdf'.format(doc_id_str))
837 os.remove(pdf_path)
838 except Exception as e:
839 self.cronjob_log.error('{0} [process error (pdf & img remove)] [task={1}] [error={2}]'.format(
840 self.log_base, task_str, traceback.format_exc()))
841
844 def handle(self, *args, **kwargs): 842 def handle(self, *args, **kwargs):
845 db.close_old_connections() 843 db.close_old_connections()
846 lock = Lock() 844 lock = Lock()
......
...@@ -165,3 +165,107 @@ class Configs(models.Model): ...@@ -165,3 +165,107 @@ class Configs(models.Model):
165 verbose_name = '配置信息' 165 verbose_name = '配置信息'
166 verbose_name_plural = verbose_name 166 verbose_name_plural = verbose_name
167 167
168
169 # 比对信息表
170 class AFCComparisonInfo(models.Model):
171 id = models.BigAutoField(primary_key=True, verbose_name="id") # 主键
172 uniq_seq = models.CharField(max_length=128, verbose_name="唯一序列号") # 索引?
173 application_id = models.CharField(max_length=64, verbose_name="申请id") # 索引
174 # CUSTOMER_TYPE = ['TCCOR', 'TCDAS', 'TCFRE', 'TCIAS', 'TCIND', 'TCSEP', 'TCURE']
175 customer_type = models.CharField(max_length=16, verbose_name="顾客类型")
176 application_version = models.SmallIntegerField(default=0, verbose_name="应用版本")
177 vehicle_status = models.CharField(max_length=16, verbose_name="车辆状况") # VEHICLE_STATUS = ['PCUSD', 'PCNEW']
178
179 individual_cus_info = models.TextField(verbose_name="个人信息")
180
181 usedcar_info = models.TextField(null=True, verbose_name="二手车信息")
182
183 corporate_cus_info = models.TextField(null=True, verbose_name="企业信息")
184
185 update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间')
186 create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') # 索引
187
188 class Meta:
189 managed = False
190 db_table = 'afc_comparison_info'
191 situ_db_label = 'afc'
192
193
194 # 比对信息表
195 class HILComparisonInfo(models.Model):
196 id = models.BigAutoField(primary_key=True, verbose_name="id") # 主键
197 uniq_seq = models.CharField(max_length=128, verbose_name="唯一序列号") # 索引?
198 application_id = models.CharField(max_length=64, verbose_name="申请id") # 索引
199 # CUSTOMER_TYPE = ['TCCOR', 'TCDAS', 'TCFRE', 'TCIAS', 'TCIND', 'TCSEP', 'TCURE']
200 customer_type = models.CharField(max_length=16, verbose_name="顾客类型")
201 application_version = models.SmallIntegerField(default=0, verbose_name="应用版本")
202 vehicle_status = models.CharField(max_length=16, verbose_name="车辆状况") # VEHICLE_STATUS = ['PCUSD', 'PCNEW']
203
204 individual_cus_info = models.TextField(verbose_name="个人信息")
205
206 usedcar_info = models.TextField(null=True, verbose_name="二手车信息")
207
208 corporate_cus_info = models.TextField(null=True, verbose_name="企业信息")
209
210 update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间')
211 create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') # 索引
212
213 class Meta:
214 managed = False
215 db_table = 'hil_comparison_info'
216 situ_db_label = 'hil'
217
218
219 # OCR结果累计表
220 class AFCOCRResult(models.Model):
221 id = models.AutoField(primary_key=True, verbose_name="id") # 主键
222 application_id = models.CharField(max_length=64, verbose_name="申请id") # 索引
223
224 bs_ocr = models.TextField(null=True, verbose_name="银行流水")
225 mvi_ocr = models.TextField(null=True, verbose_name="机动车销售统一发票")
226 ic_ocr = models.TextField(null=True, verbose_name="身份证")
227 rp_ocr = models.TextField(null=True, verbose_name="居住证")
228 bc_ocr = models.TextField(null=True, verbose_name="银行卡")
229 bl_ocr = models.TextField(null=True, verbose_name="营业执照")
230 uci_ocr = models.TextField(null=True, verbose_name="二手车发票")
231 eep_ocr = models.TextField(null=True, verbose_name="港澳台通行证")
232 dl_ocr = models.TextField(null=True, verbose_name="行驶证")
233 pp_ocr = models.TextField(null=True, verbose_name="护照")
234 mvc_ocr = models.TextField(null=True, verbose_name="机动车登记证")
235 vat_ocr = models.TextField(null=True, verbose_name="增值税发票")
236
237 update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间')
238 create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
239
240 class Meta:
241 managed = False
242 db_table = 'afc_ocr_result'
243 situ_db_label = 'afc'
244
245
246 # OCR结果累计表
247 class HILOCRResult(models.Model):
248 id = models.AutoField(primary_key=True, verbose_name="id") # 主键
249 application_id = models.CharField(max_length=64, verbose_name="申请id") # 索引
250
251 bs_ocr = models.TextField(null=True, verbose_name="银行流水")
252 mvi_ocr = models.TextField(null=True, verbose_name="机动车销售统一发票")
253 ic_ocr = models.TextField(null=True, verbose_name="身份证")
254 rp_ocr = models.TextField(null=True, verbose_name="居住证")
255 bc_ocr = models.TextField(null=True, verbose_name="银行卡")
256 bl_ocr = models.TextField(null=True, verbose_name="营业执照")
257 uci_ocr = models.TextField(null=True, verbose_name="二手车发票")
258 eep_ocr = models.TextField(null=True, verbose_name="港澳台通行证")
259 dl_ocr = models.TextField(null=True, verbose_name="行驶证")
260 pp_ocr = models.TextField(null=True, verbose_name="护照")
261 mvc_ocr = models.TextField(null=True, verbose_name="机动车登记证")
262 vat_ocr = models.TextField(null=True, verbose_name="增值税发票")
263
264 update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间')
265 create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
266
267 class Meta:
268 managed = False
269 db_table = 'hil_ocr_result'
270 situ_db_label = 'hil'
271
......
1 import locale
2 import numpy as np
3 from pandas._libs import tslib
4 from pandas._libs.tslibs.nattype import NaTType
5 from pandas.core.indexes.datetimes import DatetimeIndex
6 from openpyxl import Workbook
7 from openpyxl.styles import Border, Side, PatternFill, numbers
8 from openpyxl.utils import get_column_letter
9 from apps.doc import consts
10
11
12 class BSWorkbook(Workbook):
13
14 def __init__(self, interest_keyword, salary_keyword, loan_keyword, *args, **kwargs):
15 super().__init__(*args, **kwargs)
16 locale.setlocale(locale.LC_NUMERIC, 'en_US.UTF-8')
17 self.meta_sheet_title = '关键信息提取和展示'
18 self.blank_row = (None,)
19 self.code_header = ('页数', '电子回单验证码')
20 self.date_header = ('打印时间', '起始日期', '终止日期', '流水区间结果')
21 self.keyword_header = ('关键词', '记账日期', '金额')
22 self.interest_keyword = interest_keyword
23 self.salary_keyword = salary_keyword
24 self.loan_keyword = loan_keyword
25 self.proof_res = ('对', '错')
26 self.loan_fill = PatternFill("solid", fgColor="00FFCC00")
27 self.amount_fill = PatternFill("solid", fgColor="00FFFF00")
28 # self.bd = Side(style='thin', color="000000")
29 # self.border = Border(left=self.bd, top=self.bd, right=self.bd, bottom=self.bd)
30 self.MAX_MEAN = 31
31
32 @staticmethod
33 def sheet_prune(ws, classify):
34 ws.insert_cols(1, amount=consts.FIXED_COL_AMOUNT)
35 moved_col_set = set()
36 header_col_set = set()
37 # 根据第一行关键词排列
38 for col in range(consts.FIXED_COL_AMOUNT + 1, ws.max_column + 1):
39 header_value = ws.cell(1, col).value
40 header_col = consts.HEADERS_MAPPING.get(header_value)
41 if header_col is not None and header_col not in header_col_set:
42 letter = get_column_letter(col)
43 ws.move_range("{0}1:{0}{1}".format(letter, ws.max_row), cols=header_col - col)
44 moved_col_set.add(col)
45 header_col_set.add(header_col)
46 elif header_value in consts.BORROW_HEADERS_SET:
47 letter = get_column_letter(col)
48 ws.move_range("{0}1:{0}{1}".format(letter, ws.max_row), cols=consts.BORROW_HEADER_COL - col)
49 moved_col_set.add(col)
50 header_col_set.add(consts.BORROW_HEADER_COL)
51 elif header_value in consts.INCOME_HEADERS_SET:
52 letter = get_column_letter(col)
53 ws.move_range("{0}1:{0}{1}".format(letter, ws.max_row), cols=consts.INCOME_HEADER_COL - col)
54 moved_col_set.add(col)
55 header_col_set.add(consts.INCOME_HEADER_COL)
56 elif header_value in consts.OUTLAY_HEADERS_SET:
57 letter = get_column_letter(col)
58 ws.move_range("{0}1:{0}{1}".format(letter, ws.max_row), cols=consts.OUTLAY_HEADER_COL - col)
59 moved_col_set.add(col)
60 header_col_set.add(consts.OUTLAY_HEADER_COL)
61
62 # 缺失表头再次查找
63 for header_col in range(1, consts.FIXED_COL_AMOUNT + 1):
64 if header_col in header_col_set or header_col == consts.RESULT_HEADER_COL:
65 continue
66 fix_col = consts.CLASSIFY_LIST[classify][1][header_col - 1]
67 if fix_col is None:
68 continue
69 fix_col = fix_col + consts.FIXED_COL_AMOUNT
70 if fix_col in moved_col_set:
71 break
72 letter = get_column_letter(fix_col)
73 ws.move_range("{0}1:{0}{1}".format(letter, ws.max_row), cols=header_col - fix_col)
74
75 ws.delete_cols(consts.FIXED_COL_AMOUNT + 1, amount=ws.max_column)
76 min_row = 1 if len(moved_col_set) == 0 else 2
77 return min_row
78
79 @staticmethod
80 def month_split(dti, date_list, date_statistics):
81 month_list = []
82 idx_list = []
83 month_pre = None
84 for idx, month_str in enumerate(dti.strftime('%Y-%m')):
85 if isinstance(month_str, float):
86 continue
87 if month_str != month_pre:
88 month_list.append(month_str)
89 if month_pre is None:
90 if date_statistics:
91 date_list.append(dti[idx].date())
92 idx = 0
93 idx_list.append(idx)
94 month_pre = month_str
95 if date_statistics:
96 for idx in range(len(dti) - 1, -1, -1):
97 if isinstance(dti[idx], NaTType):
98 continue
99 date_list.append(dti[idx].date())
100 break
101 return month_list, idx_list
102
103 @staticmethod
104 def get_reverse_trend(day_idx, idx_list):
105 reverse_trend = 0
106 pre_day = None
107 for idx, day in enumerate(day_idx):
108 if np.isnan(day):
109 continue
110 if idx in idx_list or pre_day is None:
111 pre_day = day
112 continue
113 if day < pre_day:
114 reverse_trend += 1
115 pre_day = day
116 elif day > pre_day:
117 reverse_trend -= 1
118 pre_day = day
119 if reverse_trend > 0:
120 reverse_trend = 1
121 elif reverse_trend < 0:
122 reverse_trend = -1
123 return reverse_trend
124
125 def sheet_split(self, ws, month_mapping, reverse_trend_list, min_row, date_list, date_statistics):
126 for date_tuple_src in ws.iter_cols(min_col=1, max_col=1, min_row=min_row, values_only=True):
127 date_tuple = [date[:10] if isinstance(date, str) else date for date in date_tuple_src]
128 dt_array, tz_parsed = tslib.array_to_datetime(
129 np.array(date_tuple, copy=False, dtype=np.object_),
130 errors="coerce",
131 utc=False,
132 dayfirst=False,
133 yearfirst=False,
134 require_iso8601=True,
135 )
136 dti = DatetimeIndex(dt_array, tz=None, name=None)
137
138 month_list, idx_list = self.month_split(dti, date_list, date_statistics)
139
140 if len(month_list) == 0:
141 # month_info process
142 month_info = month_mapping.setdefault('xxxx-xx', [])
143 month_info.append((ws.title, min_row, ws.max_row, 0))
144 else:
145 # reverse_trend_list process
146 reverse_trend = self.get_reverse_trend(dti.day, idx_list)
147 reverse_trend_list.append(reverse_trend)
148 # month_info process
149 day_idx = dti.day
150 idx_list_max_idx = len(idx_list) - 1
151 for i, item in enumerate(month_list):
152 if i == idx_list_max_idx:
153 day_mean = np.mean(day_idx[idx_list[i]:].dropna())
154 month_mapping.setdefault(item, []).append(
155 (ws.title, idx_list[i] + min_row, ws.max_row, day_mean))
156 else:
157 day_mean = np.mean(day_idx[idx_list[i]: idx_list[i + 1]].dropna())
158 month_mapping.setdefault(item, []).append(
159 (ws.title, idx_list[i] + min_row, idx_list[i + 1] + min_row - 1, day_mean))
160
161 def build_metadata_rows(self, confidence, code, print_time, start_date, end_date):
162 if start_date is None or end_date is None:
163 timedelta = None
164 else:
165 timedelta = (end_date - start_date).days
166 metadata_rows = [
167 ('流水识别置信度', confidence),
168 self.blank_row,
169 self.code_header,
170 ]
171 metadata_rows.extend(code)
172 metadata_rows.extend(
173 [self.blank_row,
174 self.date_header,
175 (print_time, start_date, end_date, timedelta),
176 self.blank_row,
177 self.keyword_header]
178 )
179 return metadata_rows
180
181 def create_meta_sheet(self, card):
182 if self.worksheets[0].title == 'Sheet':
183 ms = self.worksheets[0]
184 ms.title = '{0}({1})'.format(self.meta_sheet_title, card[-6:])
185 else:
186 ms = self.create_sheet('{0}({1})'.format(self.meta_sheet_title, card[-6:]))
187 return ms
188
189 def build_meta_sheet(self, card, confidence, code, print_time, start_date, end_date):
190 metadata_rows = self.build_metadata_rows(confidence, code, print_time, start_date, end_date)
191 ms = self.create_meta_sheet(card)
192 for row in metadata_rows:
193 ms.append(row)
194 return ms
195
196 @staticmethod
197 def amount_format(amount_str):
198 if not isinstance(amount_str, str) or amount_str == '':
199 return amount_str
200 # 1.替换
201 res_str = amount_str.translate(consts.TRANS)
202 # 2.首字符处理
203 first_char = res_str[0]
204 if first_char in consts.ERROR_CHARS:
205 first_char = '-'
206 # 3.删除多余的-
207 res_str = first_char + res_str[1:].replace('-', '')
208 # 4.逗号与句号处理
209 if len(res_str) >= 4:
210 period_idx = len(res_str) - 3
211 if res_str[period_idx] == '.' and res_str[period_idx - 1] == ',':
212 res_str = '{0}{1}'.format(res_str[:period_idx - 1], res_str[period_idx:])
213 elif res_str[period_idx] == ',':
214 res_str = '{0}.{1}'.format(res_str[:period_idx], res_str[period_idx + 1:])
215 return res_str
216
217 def build_month_sheet(self, card, month_mapping, ms, is_reverse):
218 tmp_ws = self.create_sheet('tmp_ws')
219 for month in sorted(month_mapping.keys()):
220 # 3.1.拷贝数据
221 parts = month_mapping.get(month)
222 new_ws = self.create_sheet('{0}({1})'.format(month, card[-6:]))
223 new_ws.append(consts.FIXED_HEADERS)
224 for part in parts:
225 ws = self.get_sheet_by_name(part[0])
226 for row_value in ws.iter_rows(min_row=part[1], max_row=part[2], values_only=True):
227 new_ws.append(row_value)
228 # 3.2.提取信息、高亮
229 amount_mapping = {}
230 amount_fill_row = set()
231 for rows in new_ws.iter_rows(min_row=2):
232 summary_cell = rows[consts.SUMMARY_IDX]
233 date_cell = rows[consts.DATE_IDX]
234 amount_cell = rows[consts.AMOUNT_IDX]
235 row = summary_cell.row
236 # 关键词1提取
237 if summary_cell.value in self.interest_keyword:
238 ms.append((summary_cell.value, date_cell.value, amount_cell.value))
239 # 关键词2提取至临时表
240 elif summary_cell.value in self.salary_keyword:
241 tmp_ws.append((summary_cell.value, date_cell.value, amount_cell.value))
242 # 贷款关键词高亮
243 elif summary_cell.value in self.loan_keyword:
244 summary_cell.fill = self.loan_fill
245
246 amount_error = False
247 # 3.3.余额转数值
248 over_cell = rows[consts.OVER_IDX]
249 try:
250 over_cell.value = locale.atof(self.amount_format(over_cell.value))
251 except Exception as e:
252 amount_error = True
253 else:
254 over_cell.number_format = numbers.FORMAT_NUMBER_00
255
256 # 3.4.金额转数值
257 try:
258 try:
259 amount_cell.value = locale.atof(self.amount_format(amount_cell.value))
260 except Exception as e:
261 try:
262 amount_cell.value = locale.atof(self.amount_format(rows[consts.INCOME_IDX].value))
263 if amount_cell.value == 0:
264 raise
265 elif amount_cell.value < 0:
266 amount_cell.value = -amount_cell.value
267 except Exception as e:
268 amount_cell.value = locale.atof(self.amount_format(rows[consts.OUTLAY_IDX].value))
269 if amount_cell.value > 0:
270 amount_cell.value = -amount_cell.value
271 except Exception as e:
272 amount_error = True
273 else:
274 if rows[consts.BORROW_IDX].value in consts.BORROW_OUTLAY_SET:
275 amount_cell.value = -amount_cell.value
276 amount_cell.number_format = numbers.FORMAT_NUMBER_00
277 same_amount_mapping = amount_mapping.get(date_cell.value, {})
278 fill_rows = same_amount_mapping.get(-amount_cell.value)
279 if fill_rows:
280 amount_fill_row.add(row)
281 amount_fill_row.update(fill_rows)
282 amount_mapping.setdefault(date_cell.value, {}).setdefault(
283 amount_cell.value, []).append(row)
284
285 # 3.5.核对结果
286 if row > 2 and not amount_error:
287 if is_reverse:
288 rows[consts.RESULT_IDX].value = '=IF(D{0}=ROUND(SUM(D{1},C{0}),2), "{2}", "{3}")'.format(
289 row - 1, row, *self.proof_res)
290 else:
291 rows[consts.RESULT_IDX].value = '=IF(D{0}=ROUND(SUM(D{1},C{0}),2), "{2}", "{3}")'.format(
292 row, row - 1, *self.proof_res)
293
294 # 删除金额辅助列
295 new_ws.delete_cols(consts.BORROW_HEADER_COL, amount=new_ws.max_column)
296
297 # 3.6.同一天相同进出账高亮
298 del amount_mapping
299 for row in amount_fill_row:
300 new_ws[row][consts.AMOUNT_IDX].fill = self.amount_fill
301
302 # 关键词2信息提取
303 ms.append(self.blank_row)
304 ms.append(self.keyword_header)
305 for row in tmp_ws.iter_rows(values_only=True):
306 ms.append(row)
307 self.remove(tmp_ws)
308
309 def bs_rebuild(self, bs_summary):
310 # bs_summary = {
311 # '卡号': {
312 # 'classify': 0,
313 # 'confidence': 0.9,
314 # 'role': '柳雪',
315 # 'code': [('page', 'code')],
316 # 'print_time': 'datetime',
317 # 'start_date': 'datetime',
318 # 'end_date': 'datetime',
319 # 'sheet': ['sheet_name']
320 # }
321 # }
322 for card, summary in bs_summary.items():
323 # 1.原表修剪、排列、按照月份分割
324 start_date = summary.get('start_date')
325 end_date = summary.get('end_date')
326 date_statistics = False
327 if start_date is None or end_date is None:
328 date_statistics = True
329 date_list = []
330 month_mapping = {}
331 reverse_trend_list = []
332 for sheet in summary.get('sheet', []):
333 ws = self.get_sheet_by_name(sheet)
334 # 1.1.删除多余列、排列
335 min_row = self.sheet_prune(ws, summary.get('classify', 0))
336 # 1.2.按月份分割
337 self.sheet_split(ws, month_mapping, reverse_trend_list, min_row, date_list, date_statistics)
338
339 if date_statistics is True and len(date_list) > 1:
340 start_date = min(date_list) if start_date is None else start_date
341 end_date = max(date_list) if end_date is None else end_date
342
343 # 2.元信息提取表
344 ms = self.build_meta_sheet(card,
345 summary.get('confidence', 1),
346 summary.get('code'),
347 summary.get('print_time'),
348 start_date,
349 end_date)
350
351 # 3.创建月份表、提取/高亮关键行
352 # 倒序处理
353 is_reverse = True if sum(reverse_trend_list) > 0 else False
354 for month_list in month_mapping.values():
355 month_list.sort(key=lambda x: x[-1], reverse=is_reverse)
356
357 self.build_month_sheet(card, month_mapping, ms, is_reverse)
358
359 # 4.删除原表
360 for sheet in summary.get('sheet'):
361 self.remove(self.get_sheet_by_name(sheet))
362
363 def license_rebuild(self, license_summary, document_scheme):
364 for classify, (_, name, field_order, side_diff, scheme_diff) in consts.LICENSE_ORDER:
365 license_list = license_summary.get(classify)
366 if not license_list:
367 continue
368 ws = self.create_sheet(name)
369 if scheme_diff and document_scheme == consts.DOC_SCHEME_LIST[1]:
370 classify = consts.MVC_CLASSIFY_SE
371 for license_dict in license_list:
372 if classify == consts.IC_CLASSIFY and license_dict.get('类别') == '1':
373 license_summary.setdefault(consts.RP_CLASSIFY, []).append(license_dict)
374 continue
375 if side_diff:
376 key, field_order_yes, field_order_no = consts.FIELD_ORDER_MAP.get(classify)
377 field_order = field_order_yes if key in license_dict else field_order_no
378 for search_field, write_field in field_order:
379 ws.append((write_field, license_dict.get(search_field, '')))
380 ws.append((None, ))
381
382 def skip_img_sheet(self, skip_img):
383 if skip_img:
384 ws = self.create_sheet(consts.SKIP_IMG_SHEET_NAME)
385 ws.append(consts.SKIP_IMG_SHEET_HEADER)
386 for img_tuple in skip_img:
387 ws.append(img_tuple)
388
389 def rebuild(self, bs_summary, license_summary, skip_img, document_scheme):
390 self.bs_rebuild(bs_summary)
391 self.license_rebuild(license_summary, document_scheme)
392 self.skip_img_sheet(skip_img)
...@@ -15,11 +15,11 @@ from common import response ...@@ -15,11 +15,11 @@ from common import response
15 from common.mixins import GenericView 15 from common.mixins import GenericView
16 from common.tools.file_tools import file_write 16 from common.tools.file_tools import file_write
17 from common.redis_cache import redis_handler as rh 17 from common.redis_cache import redis_handler as rh
18 from .models import UploadDocRecords, DocStatus, PriorityApplication, GCAPRecords 18 from .models import UploadDocRecords, DocStatus, PriorityApplication, GCAPRecords, AFCComparisonInfo, HILComparisonInfo
19 from .mixins import DocHandler 19 from .mixins import DocHandler
20 from . import consts 20 from . import consts
21 from apps.account.authentication import OAuth2AuthenticationWithUser 21 from apps.account.authentication import OAuth2AuthenticationWithUser
22 from celery_compare.tasks import test 22 from celery_compare.tasks import compare
23 23
24 24
25 # restframework将request.body封装至request.data, webargs从request.data中获取参数 25 # restframework将request.body封装至request.data, webargs从request.data中获取参数
...@@ -312,8 +312,23 @@ class CompareView(GenericView): ...@@ -312,8 +312,23 @@ class CompareView(GenericView):
312 # pos上传比对信息接口 312 # pos上传比对信息接口
313 @use_args(compare_args, location='data') 313 @use_args(compare_args, location='data')
314 def post(self, request, args): 314 def post(self, request, args):
315 self.running_log.info('in') 315 # 存库
316 test.apply_async((args, ), queue='queue_compare') 316 uniq_seq = args.get('uniqSeq')
317 business_type = args.get('applicationEntity')
318 application_id = args.get('applicationId')
319 comparison_class = HILComparisonInfo if business_type in consts.HIL_SET else AFCComparisonInfo
320 comparison_class.objects.create(
321 uniq_seq=uniq_seq,
322 application_id=application_id,
323 customer_type=args.get('customerType'),
324 application_version=args.get('applicationVersion'),
325 vehicle_status=args.get('vehicleStatus'),
326 individual_cus_info=None,
327 usedcar_info=None,
328 corporate_cus_info=None,
329 )
330 # 触发比对
331 compare.apply_async((application_id, business_type, uniq_seq, None), queue='queue_compare')
317 return response.ok() 332 return response.ok()
318 333
319 post.openapi_doc = ''' 334 post.openapi_doc = '''
......
...@@ -8,4 +8,4 @@ broker = conf.CELERY_BROKER_URL ...@@ -8,4 +8,4 @@ broker = conf.CELERY_BROKER_URL
8 8
9 app = Celery('celery_compare', broker=broker, include=['celery_compare.tasks']) 9 app = Celery('celery_compare', broker=broker, include=['celery_compare.tasks'])
10 10
11 app.conf.update(worker_max_tasks_per_child=5, timezone='Asia/Shanghai')
...\ No newline at end of file ...\ No newline at end of file
11 app.conf.update(worker_max_tasks_per_child=5, timezone='Asia/Shanghai')
......
...@@ -6,7 +6,12 @@ compare_log = logging.getLogger('compare') ...@@ -6,7 +6,12 @@ compare_log = logging.getLogger('compare')
6 6
7 7
8 @app.task 8 @app.task
9 def test(info): 9 def compare(application_id, application_entity, uniq_seq, ocr_res_id):
10 doc = AFCDoc.objects.filter(id=1).first() 10 # POS: application_id, application_entity, uniq_seq, None
11 compare_log.info(doc.id) 11 # OCR: application_id, business_type(application_entity), None, ocr_res_id
12 compare_log.info(info) 12
13 # 根据application_id查找最新的比对信息,如果没有,结束
14 # 分析比对信息,需要比对的license
15 # 根据application_id查找OCR累计结果指定license字段,如果没有,结束
16 # 比对信息,将比对结果发送GCAP
17 pass
......
1 import os
2 import smtplib
3 from email import encoders
4 from email.header import Header
5 from email.mime.base import MIMEBase
6 from email.mime.multipart import MIMEMultipart
7 from email.mime.text import MIMEText
8
9 MAIL_SERVER_HOST = 'smtp.exmail.qq.com'
10 MAIL_SERVER_PORT = 25
11
12 TIME_OUT = 50
13
14
15 class MailSender:
16
17 def __init__(self, sender, pwd):
18 self.sender = sender
19 self.pwd = pwd
20 self.server = smtplib.SMTP(timeout=TIME_OUT)
21 self.server.debuglevel = 0
22 self.server.connect(host=MAIL_SERVER_HOST,
23 port=MAIL_SERVER_PORT,)
24 self.server.login(self.sender, self.pwd)
25
26 def close(self):
27 self.server.close()
28
29 def send(self, to_addrs, subject, content, file_list=[]):
30 msg = MIMEMultipart()
31
32 for att_file in file_list:
33 att = MIMEBase('application', 'octet-stream')
34 att.set_payload(open(att_file, 'rb').read())
35 encoders.encode_base64(att)
36 att.add_header('Content-Disposition',
37 'attachment',
38 filename=Header(os.path.basename(att_file), 'utf-8').encode())
39 msg.attach(att)
40
41 msg['Subject'] = Header(subject, 'utf-8')
42 msg['From'] = self.sender
43 msg['To'] = ','.join(to_addrs)
44
45 content = u'Hi:<br><br>' + \
46 content + \
47 u'<br><br>祝好!<br><br><br>本邮件为系统自动发送,请勿直接回复!<hr>'
48
49 msg.attach(MIMEText(content.encode('utf-8'), 'html', 'utf-8'))
50 self.server.sendmail(self.sender, to_addrs, msg.as_string())
51 # smtplib.SMTPServerDisconnected
52
53
54 # if __name__ == '__main__':
55 # mail_sender = MailSender()
56 # mail_sender.send(['1304057458@qq.com'], 'hello', 'world.', [])
57 # mail_sender.close()
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!