Mariia5 commited on
Commit
3478195
1 Parent(s): db2cb3d

Upload 8 files

Browse files
Files changed (8) hide show
  1. app.py +412 -0
  2. checks.py +354 -0
  3. fz93.py +27 -0
  4. garant.py +137 -0
  5. garant_check.py +126 -0
  6. helpers.py +292 -0
  7. ikz.py +32 -0
  8. requirements.txt +8 -0
app.py ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import fitz
3
+ from io import BytesIO
4
+ from termcolor import colored
5
+ from docx import Document
6
+
7
+ from helpers import get_mck, parse_doc_days, parse_pdf_oik, parse_doc_oik, get_pdf_blocks, get_doc_blocks, check_percent_before_price
8
+ from checks import check_correctness
9
+
10
+ from garant import detect_garant_pdf, detect_garant_doc, detect_garant_doc_price
11
+ from garant_check import check_garant
12
+
13
+ from ikz import get_ikz_pdf, get_ikz_doc
14
+
15
+ from fz93 import get_fz93_doc
16
+
17
+ from htbuilder import HtmlElement, div, ul, li, br, hr, a, p, img, styles, classes, fonts
18
+ from htbuilder.units import percent, px
19
+ from htbuilder.funcs import rgba, rgb
20
+
21
+
22
+
23
+
24
+ def image(src_as_string, **style):
25
+ return img(src=src_as_string, style=styles(**style))
26
+
27
+ def link(link, text, **style):
28
+ return a(_href=link, _target="_blank", style=styles(**style))(text)
29
+
30
+
31
+ def layout(*args):
32
+
33
+ style = """
34
+ <style>
35
+ # MainMenu {visibility: hidden;}
36
+ footer {visibility: hidden;}
37
+ .stApp { bottom: 40px; }
38
+ footer: after{
39
+ content:"При возникновении вопросов по работе приложения обращайтесь в поддержку e-mail: imari.iv@mail.ru"
40
+ display:block;
41
+ position:relative;
42
+ color:tomato;
43
+ padding:5px;
44
+ top:3px
45
+ }
46
+ </style>
47
+ """
48
+
49
+ style_div = styles(
50
+ #position="fixed",
51
+ left=0,
52
+ bottom=0,
53
+ margin=px(1, 1, 1, 1),
54
+ width=percent(100),
55
+ color="#FF4B4B",
56
+ text_align="center",
57
+ height="auto",
58
+ opacity=80
59
+
60
+ )
61
+
62
+ style_hr = styles(
63
+ display="block",
64
+ margin=px(8, 8, "auto", "auto"),
65
+ border_style="inset",
66
+ border_width=px(2)
67
+ )
68
+
69
+ body = p()
70
+ foot = div(
71
+ style=style_div
72
+ )(
73
+ hr(
74
+ style=style_hr
75
+ ),
76
+ body
77
+ )
78
+
79
+ st.markdown(style, unsafe_allow_html=True)
80
+
81
+ for arg in args:
82
+ if isinstance(arg, str):
83
+ body(arg)
84
+
85
+ elif isinstance(arg, HtmlElement):
86
+ body(arg)
87
+
88
+ st.markdown(str(foot), unsafe_allow_html=True)
89
+
90
+
91
+ def footer():
92
+ myargs = [
93
+ "При возникновении вопросов по работе приложения обращайтесь в поддержку ",
94
+ image('https://img.freepik.com/premium-vector/round-telegram-logo-isolated-on-white-background_469489-903.jpg?w=996', width=px(25), height=px(25)),
95
+ " @Imari_Iv ", br(),
96
+ #"🇷🇺", '&#127479;&#127482;'
97
+ image('https://img.freepik.com/free-vector/round-russian-flag-background_23-2147816636.jpg?w=996&t=st=1707289958~exp=1707290558~hmac=fb04f57b6a5c662b6df3a2c847ff8160e45f9b93b795112bccc6668ced7d5837', width=px(25), height=px(25)),
98
+ #image( "https://yoursticker.ru/wp-content/uploads/2021/12/moskovskoj-300x225.jpg", width=px(25), height=px(25)),
99
+ # " &nbsp; with ❤️ My 🏠 is 🇷🇺 :ru: Я люблю 🇷🇺 :flag_ru: by &nbsp;",
100
+ #link("https://twitter.com/ChristianKlose3", "@ChristianKlose3"),
101
+ br(),
102
+ #link("https://www.buymeacoffee.com/ChrisChross", image('https://ibb.co/d0sBsNv'), ),
103
+ ]
104
+ layout(*myargs)
105
+
106
+ def main():
107
+ st.title("Закупочный Патруль")
108
+
109
+ # Кнопка для загрузки PDF файла
110
+ pdf_files = st.file_uploader("Загрузите PDF Извещения", type=["pdf"], accept_multiple_files=True)
111
+ for pdf_file in pdf_files:
112
+ bytes_data = pdf_file.read()
113
+ pdf_doc = fitz.open(stream=bytes_data, filetype="pdf")
114
+ st.write("Файл Извещения:", pdf_file.name)
115
+ #st.write(pdf_doc[0].get_text())
116
+
117
+ # Кнопка для загрузки DOCX файла
118
+ docx_files = st.file_uploader("Загрузите DOCX файл ПК", type=["docx"], accept_multiple_files=True)
119
+ for docx_file in docx_files:
120
+ doc_bytes = docx_file.read()
121
+ doc = Document(BytesIO(doc_bytes))
122
+ #st.write(doc.paragraphs[0].text)
123
+ st.write("файл ПК:", docx_file.name)
124
+
125
+
126
+ # Кнопка начала проверки
127
+ if st.button("Проверить", type="primary"):
128
+ if pdf_file is not None and docx_file is not None:
129
+
130
+ print("=" * 80)
131
+ st.write("_" * 80)
132
+ """
133
+ ЧАСТЬ 1 "Обеспечение исполнения контракта"
134
+ """
135
+
136
+ # Логика проверки файлов и формирования комментария
137
+ try:
138
+ paragraphs = get_doc_blocks(doc)
139
+ pdf_blocks = get_pdf_blocks(pdf_doc)
140
+
141
+ percent_before_price = check_percent_before_price(paragraphs)
142
+
143
+ (
144
+ oik_pdf,
145
+ check_if_3_30_present,
146
+ check_if_24_22_present
147
+ ) = parse_pdf_oik(pdf_blocks, debug_print=False)
148
+
149
+ print(f"{check_if_3_30_present = }\n{check_if_24_22_present = }")
150
+ (
151
+ oik_docx,
152
+ ot_tseni_kontracta,
153
+ ot_nachalnoi_tseni_kontracta,
154
+ ot_max_znacenia_tseni_kontracta
155
+ ) = parse_doc_oik(paragraphs)
156
+ if oik_docx:
157
+ clean_oik_docx = (
158
+ oik_docx[0]
159
+ .replace(" процент", "%")
160
+ .replace(" %", '%')
161
+ )
162
+ else:
163
+ clean_oik_docx = ""
164
+ if oik_pdf:
165
+ clean_oik_pdf = oik_pdf[0]
166
+ else:
167
+ clean_oik_pdf = ""
168
+
169
+ MCKs = get_mck(pdf_blocks)
170
+ clean_days_docx = parse_doc_days(paragraphs)
171
+ print(f"{clean_oik_docx = }\n{clean_oik_pdf = }")
172
+ # print("MCKs", MCKs)
173
+ except Exception as ex:
174
+ #print(colored("ERROR при прочтении, пожалуйста проверьте документ!", 'magenta'))
175
+ st.write(f"ERROR при прочтении {ex}")
176
+ #st.write(" :magenta[ERROR при прочтении, пожалуйста проверьте документ!]")
177
+ clean_days_docx, MCKs, clean_oik_pdf, clean_oik_doсx = None, None, None, None
178
+ try:
179
+ if MCKs is None:
180
+ pass
181
+ elif len(MCKs) >= 1:
182
+ if len(MCKs) > 1:
183
+ print("MCK Не один")
184
+ check_correctness(
185
+ check_if_3_30_present=check_if_3_30_present,
186
+ check_if_24_22_present=check_if_24_22_present,
187
+ ot_max_znacenia_tseni_kontracta=ot_max_znacenia_tseni_kontracta,
188
+ clean_oik_pdf=clean_oik_pdf,
189
+ clean_oik_docx=clean_oik_docx,
190
+ ot_nachalnoi_tseni_kontracta=ot_nachalnoi_tseni_kontracta,
191
+ ot_tseni_kontracta=ot_tseni_kontracta,
192
+ MCKs=MCKs,
193
+ clean_days_docx=clean_days_docx,
194
+ percent_before_price=percent_before_price,
195
+ )
196
+ else:
197
+ print("MCK отсутствует!")
198
+
199
+ except Exception as ex:
200
+ # print(colored(f"ERROR при сравнении, {ex}", 'magenta'))
201
+ #st.write(":magenta[ERROR при сравнении, пожалуйста проверьте документ!]")
202
+ st.write(f"ERROR при сравнении {ex}")
203
+ # break
204
+ print("=" * 80)
205
+ st.write("_" * 80)
206
+ """
207
+ ЧАСТЬ 2 "Обеспечение гарантийных обязательств"
208
+ """
209
+
210
+ # Поле для вывода комментария после проверки
211
+ # result_comment_area = st.text_area(f"Результат проверки : {result_comment}")
212
+
213
+ # достаем параграфы текстовые из документов
214
+ paragraphs = get_doc_blocks(doc)
215
+ pdf_blocks = get_pdf_blocks(pdf_doc)
216
+
217
+ try:
218
+ garant_pdf = detect_garant_pdf(pdf_blocks, debug_print=False)
219
+ garant_docx = detect_garant_doc(paragraphs, debug_print=False)
220
+
221
+ MCKs = get_mck(pdf_blocks, debug_print=False)
222
+ price_doc = detect_garant_doc_price(paragraphs, debug_print=False)
223
+
224
+ #print(colored("ERROR при прочтении, пожалуйста проверьте документ!", 'magenta'))
225
+ except Exception as ex:
226
+ # st.write(f"ERROR при прочтении ЧАСТЬ 2, ")
227
+ st.write(f":red[ERROR при прочтении ЧАСТЬ 2, {ex}]")
228
+
229
+ check_garant(
230
+ garant_pdf=garant_pdf,
231
+ garant_docx=garant_docx,
232
+ price_doc=price_doc,
233
+ MCKs=MCKs
234
+ )
235
+ print("=" * 80)
236
+ st.write("_" * 80)
237
+ """
238
+ ЧАСТЬ 3 "ИКЗ"
239
+ """
240
+
241
+ ikz_pdf = get_ikz_pdf(pdf_blocks)
242
+ ikz_docx = get_ikz_doc(doc)
243
+ if ikz_docx and ikz_pdf:
244
+ ikz_docx_clean = set(
245
+ [el.replace("-", '') for el in ikz_docx]
246
+ )
247
+ ikz_pdf_clean = set(
248
+ [el.replace("-", '') for el in ikz_pdf]
249
+ )
250
+ if ikz_docx_clean == ikz_pdf_clean:
251
+ # print(colored("РАВНЫ", 'green'))
252
+ st.write(":green[РАВНЫ]")
253
+ # st.write("РАВНЫ")
254
+ else:
255
+ # print(colored("ОШИБКА", 'magenta'))
256
+ st.write(":red[ОШИБКА]")
257
+ # st.write("ОШИБКА")
258
+ for el in sorted(ikz_docx_clean):
259
+ if el not in ikz_pdf_clean:
260
+ # print(f"ИКЗ {el} присутствует в .docx, но не в .pdf")
261
+ st.write(f"ИКЗ {el} присутствует в .docx, но не в .pdf")
262
+ print("-" * 60)
263
+ st.write("-" * 60)
264
+ for el in sorted(ikz_pdf_clean):
265
+ if el not in ikz_docx_clean:
266
+ # print(f"ИКЗ {el} присутствует в .pdf, но не в .docx")
267
+ st.write(f"ИКЗ {el} присутствует в .pdf, но не в .docx")
268
+ else:
269
+ # print(colored("ПУСТОЕ ЗНАЧЕНИЕ", 'magenta'))
270
+ st.write(":red[ПУСТОЕ ЗНАЧЕНИЕ]")
271
+ # st.write("ПУСТОЕ ЗНАЧЕНИЕ")
272
+
273
+ print("=" * 80)
274
+ st.write("_" * 80)
275
+ """
276
+ ЧАСТЬ 4 "часть 1 статьи 93 ФЗ-44 в ПК"
277
+ """
278
+
279
+ fz93_docx = get_fz93_doc(doc)
280
+ if fz93_docx: # проверка на пустоту, если есть ст.93 - ОШИБКА
281
+ print(colored("ОШИБКА", 'magenta'))
282
+ st.write(":red[ОШИБКА]")
283
+ print("ч. 1 ст. 93 ФЗ в ПК")
284
+ st.write("ч. 1 ст. 93 ФЗ в ПК")
285
+ else:
286
+ print(colored("ВЕРНО", 'green'))
287
+ st.write(":green[ВЕРНО]")
288
+
289
+
290
+
291
+
292
+
293
+
294
+
295
+ st.header(':blue[ККП МО]:arrow_upper_right:',anchor=None, divider="blue")
296
+
297
+ # expander = st.expander("Информация")
298
+ #
299
+ # expander.write("**Руководство пользователя**")
300
+ # expander.write(" :white_check_mark: Для проверки вашей закупочной документации перед публикацией поместите в "
301
+ # "первый слот проект Извещения в формате PDF, во второй слот добавьте проект "
302
+ # "Контракта в формате DOCX.")
303
+ # expander.write(" :green[Ваш документ не должен быть создан в версии Microsoft Word 97–2003 (.doc)] ")
304
+ # expander.write(" :white_check_mark: Нажмите кнопку :red[Проверить] ")
305
+ # expander.write(" :white_check_mark: Посмотрите на результаты проверки блоков закупочной документации. "
306
+ # " Если ответ :green[ВЕРНО] или :green[РАВНЫ], значит ошибок не обнаружено.")
307
+ # expander.write( " :white_check_mark: В случае получения результата :red[ОШИБКА] проверьте соответсвующий блок вашей документации.")
308
+ # expander.write(":blue[ЧАСТЬ 1 ]")
309
+ # expander.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части"
310
+ # " 'Обеспечения исполнения Контракта'.")
311
+ #
312
+ # expander.write("В случае получения результата :red[ОШИБКА], проверьте ваш документ в соответствии с появившейся инструкцией."
313
+ # " Не забудьте проверить корректность вычислений.")
314
+ # expander.write("В случае получения результата :red[ОШИБКА в днях OIK], проверьте правильность срока возврата обеспечения.")
315
+ # expander.write("В случае получения результата :red[ERROR при прочтении, пожалуйста проверьте документ!] или "
316
+ # " :red[ERROR при сравнении] - проверьте наличие данного блока в вашей документации.")
317
+ #
318
+ #
319
+ # expander.write(":blue[ЧАСТЬ 2 ]")
320
+ # expander.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части"
321
+ # " 'Обеспечения гарантийных обязательств'.")
322
+ # expander.write("В случае получения результата :red[ОШИБКА], проверьте данный блок в вашем документе в соответствии с появившейся инструкцией."
323
+ # " Не забудьте проверить корректность вычислений.")
324
+ # expander.write("В случае получения результата :red[ERROR при прочтении ЧАСТЬ 2] "
325
+ # " - проверьте наличие данного блока в вашей документации.")
326
+ # expander.write(":blue[ЧАСТЬ 3 ]")
327
+ # expander.write("В данном блоке проверяется соответствие кодов ИКЗ в проекте Контракта с кодами Извещения в части"
328
+ # " 'Идентификационные коды закупки'.")
329
+ # expander.write("В случае получения результата :red[ОШИБКА], проверьте не совпавшие коды, указанные под ним.")
330
+ # expander.write(":blue[ЧАСТЬ 4 ]")
331
+ # expander.write("В данном блоке проверяется отсутствие в проекте Контракта указания на часть 1 статьи 93 ФЗ-44."
332
+ # " В случае получения результата :red[ОШИБКА], удалите из вашего проекта Контракта данную статью.")
333
+ # expander.write(" :white_check_mark: Если вам не удалось найти ошибку или возникли иные вопросы по работе приложения"
334
+ # " - обратитесь в поддержку.")
335
+ # expander.write(":blue[Для скрытия данного блока повторно нажмите на информационную кнопку]")
336
+
337
+
338
+
339
+
340
+
341
+
342
+ # Проверяем, существует ли состояние session_state.text_widget и инициализируем его, если нет
343
+ if "text_widget" not in st.session_state:
344
+ st.session_state.text_widget = False
345
+ #
346
+ # # Создаем кнопку для открытия/закрытия виджета
347
+ if st.button("i"):
348
+ st.session_state.text_widget = not st.session_state.text_widget
349
+ #
350
+ # # Отображаем виджет, если флаг равен True
351
+ if st.session_state.text_widget:
352
+ container = st.container(border=True)
353
+ container.write("**Руководство пользователя**")
354
+ container.write(" :white_check_mark: Для проверки вашей закупочной документации поместите в "
355
+ "первый слот проект Извещения в формате PDF, во второй слот добавьте проект "
356
+ "Контракта в формате DOCX.")
357
+ container.write(" :green[Ваш документ не должен быть создан в версии Microsoft Word 97–2003 (.doc)] ")
358
+ container.write(" :white_check_mark: Нажмите кнопку :red[Проверить] ")
359
+ container.write(" :white_check_mark: Посмотрите на результаты проверки блоков закупочной документации. "
360
+ " Если ответ :green[ВЕРНО] или :green[РАВНЫ], значит ошибок не обнаружено.")
361
+ container.write( " :white_check_mark: В случае получения результата :red[ОШИБКА] проверьте соответсвующий блок вашей документации.")
362
+ #
363
+ #
364
+ #
365
+ container.write(":blue[ЧАСТЬ 1 ]")
366
+ container.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части"
367
+ " 'Обеспечения исполнения Контракта'.")
368
+ #
369
+ container.write("В случае получения результата :red[ОШИБКА]")
370
+
371
+ container.write( " :red[ 1. Если Обеспечение исполнения Контракта указано в Приложении к проекту Контракта проверьте его самостоятельно и проигнорируйте сообщение об ошибке]")
372
+ container.write( " 2. Проверьте ваш документ в соответствии с появившейся инструкцией.")
373
+ container.write( " 3. Не забудьте проверить корректность вычислений.")
374
+ container.write("В случае получения результата :red[ОШИБКА в днях OIK], проверьте правильность срока возврата обеспечения.")
375
+ container.write("В случае получения результата :red[ERROR при прочтении, пожалуйста проверьте документ!] или "
376
+ " :red[ERROR при сравнении] - проверьте наличие данного блока в вашей документации.")
377
+ #
378
+ #
379
+ container.write(":blue[ЧАСТЬ 2 ]")
380
+ container.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части"
381
+ " 'Обеспечения гарантийных обязательств'.")
382
+ container.write("В случае получения результата :red[ОШИБКА], проверьте данный блок в вашем документе в соответствии с появившейся инструкцией."
383
+ " Не забудьте проверить корректность вычислений.")
384
+ container.write("В случае получения результата :red[ERROR при прочтении ЧАСТЬ 2] "
385
+ " - проверьте наличие данного блока в вашей документации.")
386
+ container.write(":blue[ЧАСТЬ 3 ]")
387
+ container.write("В данном блоке проверяется соответствие кодов ИКЗ в проекте Контракта с кодами Извещения в части"
388
+ " 'Идентификационные коды закупки'.")
389
+ container.write("В случае получения результата :red[ОШИБКА], проверьте не совпавшие коды, указанные под ним.")
390
+ container.write(":blue[ЧАСТЬ 4 ]")
391
+ container.write("В данном блоке проверяется отсутствие в проекте Контракта указания на часть 1 статьи 93 ФЗ-44."
392
+ " В случае получения результата :red[ОШИБКА], удалите из вашего проекта Контракта данную статью.")
393
+ container.write(" :white_check_mark: Если вам не удалось найти ошибку или возникли иные вопросы по работе приложения"
394
+ " - обратитесь в поддержку.")
395
+ container.write(":blue[Для скрытия данного блока повторно нажмите на информационную кнопку]")
396
+
397
+
398
+
399
+
400
+
401
+ #st.markdown("Here's a bouquet &mdash;\
402
+ # :tulip::cherry_blossom::rose::hibiscus::sunflower::blossom:")
403
+
404
+
405
+
406
+
407
+
408
+ if __name__ == "__main__":
409
+ main()
410
+ footer()
411
+ # show_info()
412
+
checks.py ADDED
@@ -0,0 +1,354 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from termcolor import colored
3
+
4
+
5
+ def check_0th_case(
6
+ check_if_3_30_present,
7
+ clean_oik_docx,
8
+ clean_oik_pdf,
9
+ clean_days_docx,
10
+ ):
11
+ print(colored("check_0th_case", 'blue'),
12
+ f"\t{check_if_3_30_present = }",
13
+ f"\t{clean_oik_docx = }",
14
+ f"\t{clean_oik_pdf = }",
15
+ f"\t{clean_days_docx = }", sep="\n")
16
+
17
+ if all([
18
+ check_if_3_30_present == True,
19
+ clean_oik_docx not in ["не установлены", "не устанавливается"],
20
+ clean_oik_pdf != "не требуется"
21
+ ]):
22
+ return clean_days_docx == 15 # (== True if clean_days_docx == 15 else False)
23
+
24
+ return None
25
+
26
+
27
+ def check_1st_case(
28
+ clean_oik_pdf,
29
+ clean_oik_docx,
30
+ ot_nachalnoi_tseni_kontracta,
31
+ ot_tseni_kontracta,
32
+ MCKs,
33
+
34
+ ):
35
+ print(colored("case1", 'blue'),
36
+ f"\t{clean_oik_pdf = }",
37
+ f"\t{clean_oik_docx = }",
38
+ f"\t{MCKs = }", sep="\n")
39
+
40
+ print(f"{ot_nachalnoi_tseni_kontracta = }")
41
+ print(f"{ot_tseni_kontracta = }")
42
+ correct = False
43
+ if all([
44
+ "Российский рубль" in clean_oik_pdf,
45
+ ot_nachalnoi_tseni_kontracta,
46
+ "%" in clean_oik_docx,
47
+ ]):
48
+ clean_oik_pdf = float(clean_oik_pdf.removesuffix(" Российский рубль"))
49
+ for MCK in MCKs:
50
+ price_docx = float(
51
+ clean_oik_docx.strip("% ").strip("(десять) ").strip("(пять) ").strip("(тридцать) ")) * MCK / 100
52
+ # print("СРАВНЕНИЕ", clean_oik_pdf, "||", price_docx)
53
+ # print(clean_oik_pdf)
54
+ if abs(clean_oik_pdf - price_docx) < 3:
55
+ #print(colored("ВЕРНО", 'green'))
56
+ st.write(":green[ВЕРНО]")
57
+ #st.write("ВЕРНО")
58
+ correct = True
59
+
60
+ if not correct:
61
+ #print(colored("ОШИБКА", 'magenta'))
62
+ st.write(":red[ОШИБКА]")
63
+ #st.write("ОШИБКА")
64
+ st.write("Если не указаны ч.24 ст.22 и ч.3 ст.30, то обеспечение исполнения контракта устанавливается от НАЧАЛЬНОЙ (максимальной) цены")
65
+ st.write("Условие Извещения (Российский рубль) = Условие ПК % * НМЦК")
66
+ st.write("Условие Извещения 'не требуется' = Условие ПК 'не установлено'")
67
+ #st.write("Срок возврата обеспечения 30 дней")
68
+
69
+
70
+ def check_2nd_case(
71
+ clean_oik_pdf,
72
+ clean_oik_docx,
73
+ ot_tseni_kontracta,
74
+ MCKs,
75
+ clean_days_docx,
76
+ check_if_3_30_present,
77
+
78
+ ):
79
+ print(colored("case2", 'blue'),
80
+ f"\t{clean_oik_pdf = }",
81
+ f"\t{clean_oik_docx = }",
82
+ f"\t{MCKs = }", sep="\n")
83
+ correct = False
84
+ if all([
85
+ "%" in clean_oik_pdf,
86
+ "%" in clean_oik_docx,
87
+
88
+ ]):
89
+
90
+ print("СРАВНЕНИЕ", clean_oik_pdf, "||", float(clean_oik_docx.strip("% ")))
91
+ clean_oik_pdf = float(
92
+ clean_oik_pdf.removesuffix(" Российский рубль").strip(" %"))
93
+ print(clean_oik_pdf)
94
+ if abs(clean_oik_pdf - float(clean_oik_docx.strip("% ").strip("(десять) ").strip("(пять) ").strip(
95
+ "(тридцать) "))) < 3:
96
+ if ot_tseni_kontracta:
97
+ check0 = check_0th_case(
98
+ check_if_3_30_present,
99
+ clean_oik_docx,
100
+ clean_oik_pdf,
101
+ clean_days_docx,
102
+ )
103
+ if check0 == True:
104
+ # print(colored("ВЕРНО", 'green'))
105
+ st.write(":green[ВЕРНО]")
106
+ # st.write("ВЕРНО")
107
+ correct = True
108
+ elif check0 == False:
109
+ #print(colored("ОШИБКА в днях OIK", 'magenta'))
110
+ st.write(":red[ОШИБКА в днях]")
111
+ #st.write("ОШИБКА в днях")
112
+ st.write("При выборе ч.3.ст.30 возврат обеспечения исполнения контракта - 15 дней")
113
+
114
+ if not correct:
115
+ # print(colored("ОШИБКА", 'magenta'))
116
+ st.write(":red[ОШИБКА]")
117
+ # st.write("ОШИБКА")
118
+ st.write("Условие Извещения % = Условие ПК %")
119
+ st.write("При указании ч.3 ст.30 и ч.24 ст.22 обеспечение исполнения контракта устанавливается от ЦЕНЫ КОНТРАКТА")
120
+ st.write("Условие Извещения 'не требуется' = Условие ПК 'не установлено'")
121
+
122
+
123
+
124
+
125
+ def check_3rd_case(
126
+ clean_oik_pdf,
127
+ clean_oik_docx,
128
+ ot_nachalnoi_tseni_kontracta,
129
+ ot_max_znacenia_tseni_kontracta,
130
+ MCKs,
131
+ ):
132
+ print(colored("case3", 'blue'),
133
+ f"\t{clean_oik_pdf = }",
134
+ f"\t{clean_oik_docx = }",
135
+ f"\t{MCKs = }", sep="\n")
136
+ correct = False
137
+ if all([
138
+ "Российский рубль" in clean_oik_pdf,
139
+ "%" in clean_oik_docx,
140
+ ]):
141
+ clean_oik_pdf = float(clean_oik_pdf.removesuffix(" Российский рубль"))
142
+ print(f"clean_oik_pdf: {clean_oik_pdf}")
143
+ for MCK in MCKs:
144
+
145
+ if abs(clean_oik_pdf - (float(clean_oik_docx.strip("% ").strip("(десять) ").strip("(пять) ").strip("(тридцать) ")) * MCK / 100)) < 3:
146
+ if ot_nachalnoi_tseni_kontracta or ot_max_znacenia_tseni_kontracta:
147
+ # print(colored("ВЕРНО",'green'))
148
+ st.write(":green[ВЕРНО]")
149
+ # st.write("ВЕРНО")
150
+ correct = True
151
+ if not correct:
152
+ # print(colored("ОШИБКА",'magenta'))
153
+ st.write(":red[ОШИБКА]")
154
+ #st.write("ОШИБКА")
155
+ st.write("При указании ч.24 ст.22 и отсутствии ч.3 ст.30 обеспечение исполнения контракта устанавливается от МАКСИМАЛЬНОГО ЗНАЧЕНИЯ ЦЕНЫ КОНТРАКТА")
156
+ st.write("Условие Извещения (Российский рубль) = Условие ПК % * НМЦК")
157
+ st.write("Условие Извещения 'не требуется' = Условие ПК 'не установлено'")
158
+
159
+
160
+
161
+
162
+ def check_4th_case(
163
+ clean_oik_pdf,
164
+ clean_oik_docx,
165
+ ot_nachalnoi_tseni_kontracta,
166
+ ot_tseni_kontracta,
167
+ MCKs,
168
+ clean_days_docx,
169
+ check_if_3_30_present,
170
+ percent_before_price
171
+ ):
172
+ print(colored("case4", 'blue'),
173
+ f"\t{clean_oik_pdf = }",
174
+ f"\t{clean_oik_docx = }",
175
+ f"\t{MCKs = }",
176
+ f"\t{ot_nachalnoi_tseni_kontracta = }",
177
+ f"\t{ot_tseni_kontracta = }",
178
+ sep="\n")
179
+
180
+ correct = False
181
+ if all([
182
+ percent_before_price == False,
183
+ "%" in clean_oik_pdf,
184
+ "%" in clean_oik_docx,
185
+ ]):
186
+ if float(clean_oik_pdf.strip("% ")) == float(clean_oik_docx.strip("% ").strip("(десять) ").strip("(пять) ").strip("(тридцать) ")):
187
+ if ot_tseni_kontracta and not ot_nachalnoi_tseni_kontracta:
188
+ check0 = check_0th_case(
189
+ check_if_3_30_present,
190
+ clean_oik_docx,
191
+ clean_oik_pdf,
192
+ clean_days_docx,
193
+ )
194
+ print("check0", check0)
195
+ if check0 == True:
196
+ # print(colored("ВЕРНО",'green'))
197
+ st.write(":green[ВЕРНО]")
198
+ # st.write("ВЕРНО")
199
+
200
+ correct = True
201
+ elif check0 == False:
202
+ # print(colored("ОШИБКА в днях OIK",'magenta'))
203
+ st.write(":red[ОШИБКА в днях]")
204
+ # st.write("ОШИБКА в днях")
205
+ st.write("При выборе ч.3.ст.30 возврат обеспечения исполнения контракта - 15 дней")
206
+
207
+ if not correct:
208
+ # print(colored("ОШИБКА",'magenta'))
209
+ # st.write("ОШИБКА")
210
+ st.write(":red[ОШИБКА]")
211
+ st.write("При указании ч.3 ст.30 обеспечение исполнения контракта устанавливается от ЦЕНЫ КОНТРАКТА")
212
+ st.write("Условие Извещения % = Условие ПК %")
213
+ st.write("Условие Извещения 'не требуется' = Условие ПК 'не установлено'")
214
+
215
+
216
+ def check_correctness(
217
+ check_if_3_30_present,
218
+ check_if_24_22_present,
219
+ clean_oik_pdf,
220
+ clean_oik_docx,
221
+ ot_nachalnoi_tseni_kontracta,
222
+ ot_tseni_kontracta,
223
+ ot_max_znacenia_tseni_kontracta,
224
+ MCKs,
225
+ clean_days_docx,
226
+ percent_before_price
227
+ ):
228
+ # """
229
+ # === case5 ===
230
+ # elif 'Обеспечение исполнения контракта не требуется' in pdf and "Требования к обеспечению исполнению Контракта не установлены" in docx:
231
+ # if "не требуется"="не установлены":
232
+ # print("ВЕРНО")
233
+ # else:
234
+ # print ("ОШИБКА")
235
+ # break
236
+ # """
237
+ if clean_oik_pdf == "не требуется" and clean_oik_docx == "не установлены" or \
238
+ clean_oik_pdf == "не требуется" and clean_oik_docx == "не устанавливается":
239
+ print(
240
+ colored("case5", 'blue'),
241
+ f"\t{clean_oik_pdf = }",
242
+ f"\t{clean_oik_docx = }", sep="\n")
243
+ #print(colored("ВЕРНО", 'green'))
244
+ st.write(":green[ВЕРНО]")
245
+ # st.write("ВЕРНО")
246
+ check0 = check_0th_case(
247
+ check_if_3_30_present=check_if_3_30_present,
248
+ clean_oik_docx=clean_oik_docx,
249
+ clean_oik_pdf=clean_oik_pdf,
250
+ clean_days_docx=clean_days_docx,
251
+ )
252
+ if check0 == True:
253
+ # print(colored("ВЕРНО", 'green'))
254
+ st.write(":green[ВЕРНО]")
255
+ # st.write("ВЕРНО")
256
+ correct = True
257
+ elif check0 == False:
258
+ # print(colored("ОШИБКА в днях OIK", 'magenta'))
259
+ st.write(":red[ОШИБКА в днях]")
260
+ # st.write("ОШИБКА в днях")
261
+ st.write("При выборе ч.3 ст.30 возврат обеспечения - 15 дней")
262
+
263
+ # """
264
+ # === case1 ===
265
+ # if "ч. 24 ст. 22" and "ч. 3 ст. 30" not in pdf:
266
+ # if oik.pdf Российский рубль = oik.docx %|процент(ов,а) от НАЧАЛЬНОЙ МАКСИМАЛЬНОЙ (НМЦ) docx *"Начальная (максимальная) цена ".pdf Российский рубль:
267
+ # print("ВЕРНО")
268
+ # else:
269
+ # print ("ОШИБКА")
270
+ # break
271
+ # """
272
+ elif not check_if_3_30_present and not check_if_24_22_present:
273
+ check_1st_case(
274
+ clean_oik_pdf=clean_oik_pdf,
275
+ clean_oik_docx=clean_oik_docx,
276
+ ot_nachalnoi_tseni_kontracta=ot_nachalnoi_tseni_kontracta,
277
+ ot_tseni_kontracta=ot_tseni_kontracta,
278
+ MCKs=MCKs,
279
+ )
280
+
281
+ # """
282
+ # === case2 ===
283
+ # elif "ч. 3 ст. 30" and "ч. 24 ст. 22" in pdf :
284
+ # if oik.pdf % = oik.docx %|процент(ов,а) от ЦЕНЫ КОНТРАКТА:
285
+ # print("ВЕРНО")
286
+ # else:
287
+ # print ("ОШИБКА")
288
+ # break
289
+ # """
290
+ elif check_if_3_30_present and check_if_24_22_present:
291
+ check_2nd_case(
292
+ clean_oik_pdf=clean_oik_pdf,
293
+ clean_oik_docx=clean_oik_docx,
294
+ # ot_nachalnoi_tseni_kontracta,
295
+ ot_tseni_kontracta=ot_tseni_kontracta,
296
+ MCKs=MCKs,
297
+ clean_days_docx=clean_days_docx,
298
+ check_if_3_30_present=check_if_3_30_present,
299
+
300
+ )
301
+
302
+ # """
303
+ # === case3 ===
304
+ # elif "ч. 24 ст. 22" in pdf and "ч. 3 ст. 30" not in pdf:
305
+ # if oik.pdf Российский рубль = "Максимальное значение цены контракта".pdf * %|процент(ов,а) от ЦЕНЫ контракта.docx:
306
+ # print("ВЕРНО")
307
+ # else:
308
+ # print ("ОШИБКА")
309
+ # break
310
+ # """
311
+ elif check_if_24_22_present and not check_if_3_30_present:
312
+ check_3rd_case(
313
+ clean_oik_pdf=clean_oik_pdf,
314
+ clean_oik_docx=clean_oik_docx,
315
+ ot_nachalnoi_tseni_kontracta=ot_nachalnoi_tseni_kontracta,
316
+ ot_max_znacenia_tseni_kontracta=ot_max_znacenia_tseni_kontracta,
317
+ # ot_tseni_kontracta,
318
+ MCKs=MCKs,
319
+ )
320
+
321
+ # """
322
+ # === case4 ===
323
+ # elif "ч. 3 ст. 30" in pdf and "ч. 24 ст. 22" not in pdf:
324
+ # if oik.pdf % = oik.docx %|процент(ов,а) от ЦЕНЫ контракта:
325
+ # print("ВЕРНО")
326
+ # else:
327
+ # print ("ОШИБКА")
328
+ # break
329
+ # """
330
+ elif check_if_3_30_present and not check_if_24_22_present:
331
+ check_4th_case(
332
+ clean_oik_pdf=clean_oik_pdf,
333
+ clean_oik_docx=clean_oik_docx,
334
+ ot_nachalnoi_tseni_kontracta=ot_nachalnoi_tseni_kontracta,
335
+ ot_tseni_kontracta=ot_tseni_kontracta,
336
+ MCKs=MCKs,
337
+ clean_days_docx=clean_days_docx,
338
+ check_if_3_30_present=check_if_3_30_present,
339
+ percent_before_price=percent_before_price
340
+ )
341
+
342
+ # """
343
+ # === case7 ===
344
+ # elif "обеспечение исполнения контракта» приложения 2 к Контракту" in docx:
345
+ # print("ERROR Требуется проверка ")
346
+ # else:
347
+ # print("ERROR Требуется проверка")
348
+ # break
349
+ # """
350
+ else:
351
+ # print(colored("ERROR Требуется проверка", 'magenta'))
352
+ st.write(":red[ERROR Требуется проверка]")
353
+ # st.write("ERROR Требуется проверка")
354
+ # break
fz93.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from docx import Document
3
+ from helpers import get_doc_blocks
4
+
5
+
6
+ def get_fz93_doc(doc):
7
+ fz93_docx = set()
8
+ paragraphs = get_doc_blocks(doc)
9
+ fz93_doc_regex = ["части 1 статьи 93 Федерального закона",
10
+ "ч. 1 ст. 93",
11
+ "частью 1 статьи 93 Федерального закона"]
12
+
13
+ for docpara in paragraphs:
14
+ for val in fz93_doc_regex:
15
+ fz93_docx.update(
16
+ re.findall(val, docpara)
17
+ )
18
+ #doc = Document(file_name_doc)
19
+ for table in doc.tables:
20
+ for row in table.rows:
21
+ for cell in row.cells:
22
+ for para in cell.paragraphs:
23
+ for val in fz93_doc_regex:
24
+ fz93_docx.update(
25
+ re.findall(val, para.text)
26
+ )
27
+ return fz93_docx
garant.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+
4
+ garant_pdf_regex = [
5
+ "\d+(?:\.\d{2})?%",
6
+
7
+ "\d+(?:\.\d{2})? Российский рубль",
8
+ "((?:не требуется)|(?:не установлены))"
9
+ ]
10
+
11
+
12
+ def normalize_whitespaces(text):
13
+ return re.sub("\s+", "", text).lower()
14
+
15
+
16
+ value1 = normalize_whitespaces('Обеспечение гарантийных обязательств')
17
+ value2 = normalize_whitespaces('Обеспечение гарантийных')
18
+
19
+
20
+ def detect_garant_pdf(pdf_blocks, debug_print):
21
+ garant_pdf = None
22
+
23
+ for i, block in enumerate(pdf_blocks):
24
+ check = (
25
+ value1 in normalize_whitespaces(block)
26
+ and value1 in normalize_whitespaces(pdf_blocks[i + 1])
27
+ or value2 in normalize_whitespaces(block)
28
+ and value2 in normalize_whitespaces(pdf_blocks[i + 1])
29
+ )
30
+ if check:
31
+ text = re.sub("\s+", " ", pdf_blocks[i + 1])
32
+ if "не требуется" in text:
33
+ garant_pdf = "не требуется"
34
+ elif "не" in text:
35
+ garant_pdf = "не требуется"
36
+ else:
37
+ paragraphs_to_check = pdf_blocks[i + 2] + "\n" + pdf_blocks[i + 3]
38
+ if debug_print:
39
+ print("PDF_TEXT", paragraphs_to_check)
40
+ print("-" * 70)
41
+ for val in garant_pdf_regex:
42
+ if garant_pdf := re.findall(val, paragraphs_to_check):
43
+ garant_pdf = garant_pdf[0]
44
+ break
45
+ return garant_pdf
46
+
47
+
48
+
49
+ docx_regex = [
50
+ "\d+(?:[.,]\d{1})? ?%",
51
+ r"\d+(?:[.,]\d{1})? ?процент",
52
+ "(\d{1,3} ?%) начальной",
53
+ "не установлен(?:ы|о)",
54
+ "не устанавливается",
55
+ "(\d{1,3} ?%) от начальной",
56
+ "(\d{1,3} ?%) от цены",
57
+ "(\d{1,3} ?%) процент",
58
+ "\d{1,3} процент",
59
+ ]
60
+
61
+
62
+ def detect_garant_doc(paragraphs, debug_print=False):
63
+ garant_docx = None
64
+
65
+ for i, docpara in enumerate(paragraphs):
66
+ if "Обеспечение гарантийных обязательств" == docpara:
67
+ text = paragraphs[i + 1].removeprefix("10. Обеспечение гарантийных обязательств")
68
+ if debug_print:
69
+ print("DOCX_TEXT", text)
70
+ print("-" * 70)
71
+ for val in docx_regex:
72
+ if garant_docx := re.findall(val, text):
73
+ break
74
+ else:
75
+ for string in [
76
+ "размер обеспечения гарантийных обязательств",
77
+ "обеспечение гарантийных обязательств в размере",
78
+ "требования к обеспечению гарантийных обязательств не установлены",
79
+ "обеспечение гарантийных обязательств не устанавливается",
80
+ "размер обеспечения гарантийных обязательств",
81
+ "обеспечения гарантийных обязательств в размере",
82
+
83
+ ]:
84
+ if not garant_docx and string.lower() in docpara.lower():
85
+ for val in docx_regex:
86
+ if garant_docx := re.findall(val, paragraphs[i]):
87
+ break
88
+
89
+ if garant_docx:
90
+ garant_docx = (
91
+ garant_docx[0]
92
+ .replace("процент", "%")
93
+ .replace(",", ".")
94
+ )
95
+ return garant_docx
96
+
97
+
98
+ docx_regex_price = [
99
+ r"\d[\d ]+(?:[.,] ?\d{2})? ?руб",
100
+ "не установлен(?:ы|о)",
101
+ "не устанавливается" ,
102
+ ]
103
+
104
+
105
+ def detect_garant_doc_price(paragraphs, debug_print=False):
106
+ price_doc = None
107
+ for i, docpara in enumerate(paragraphs):
108
+ if "Обеспечение гарантийных обязательств" == docpara:
109
+ text = paragraphs[i + 1].removeprefix("10. Обеспечение гарантийных обязательств")
110
+ for val in docx_regex_price:
111
+ if price_doc := re.findall(val, text):
112
+ # return text
113
+ if debug_print:
114
+ print("GARANT_DOC_PRICE: ", text)
115
+ break
116
+
117
+ else:
118
+ for string in [
119
+ "размер обеспечения гарантийных обязательств",
120
+ "обеспечение гарантийных обязательств в размере",
121
+ "требования к обеспечению гарантийных обязательств не установлены",
122
+ "обеспечение гарантийных обязательств не устанавливается",
123
+ "размер обеспечения гарантийных обязательств",
124
+ "обеспечения гарантийных обязательств в размере",
125
+ "подлежит предоставлению обеспечение гарантийных обязательств в размере"
126
+ ]:
127
+ if not price_doc and string.lower() in docpara.lower():
128
+ for val in docx_regex_price:
129
+ if price_doc := re.findall(val, paragraphs[i]):
130
+ if debug_print:
131
+ print("GARANT_DOC_PRICE: ", paragraphs[i])
132
+ break
133
+ if not price_doc:
134
+ price_doc = None
135
+ else:
136
+ price_doc = price_doc[0]
137
+ return price_doc
garant_check.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from termcolor import colored
3
+
4
+ def check_garant(
5
+ garant_pdf,
6
+ garant_docx,
7
+ price_doc,
8
+ MCKs
9
+ ):
10
+ print("-" * 80)
11
+ print(
12
+ f"garant_pdf: {garant_pdf}\n" +
13
+ f"garant_docx: {garant_docx}\n" +
14
+ f"price_doc: {price_doc}\n" +
15
+ f"MCKs: {MCKs}"
16
+ )
17
+
18
+ correct = False
19
+ # """
20
+ # случай 1
21
+ # ""
22
+ if all([
23
+ garant_pdf == "не требуется",
24
+ garant_docx == None,
25
+ price_doc == None
26
+ ]) or all([
27
+ garant_pdf == "не требуется",
28
+ garant_docx == "не установлены",
29
+ price_doc == "не установлены"
30
+ ]) or all([
31
+ garant_pdf == "не требуется",
32
+ garant_docx == "не установлены",
33
+ price_doc == "не устанавливается"
34
+ ]) or all([
35
+ garant_pdf == "не требуется",
36
+ garant_docx == "не устанавливается",
37
+ price_doc == "не устанавливается"
38
+ ]):
39
+ # print("ВЕРНО", 'green')
40
+ st.write(":green[ВЕРНО]")
41
+ # st.write("ВЕРНО")
42
+ correct = True
43
+ # """
44
+ # случай 2
45
+ # """
46
+ elif garant_docx and price_doc and all([
47
+ "Российский рубль" in garant_pdf,
48
+ "%" in garant_docx,
49
+ "руб" in price_doc
50
+ ]):
51
+ clean_garant_docx = garant_docx.replace("процент", "%").replace(" ", '')
52
+ clean_price_doc = float(price_doc.replace(" ", "").split(",")[0].replace("руб", ""))
53
+ clean_garant_pdf = float(garant_pdf.removesuffix("Российский рубль").strip())
54
+ for MCK in MCKs:
55
+ procent_garant_docx = float(clean_garant_docx.strip("% ")) * MCK / 100
56
+ print("СРАВНЕНИЕ",
57
+ f"\tprocent_garant_docx: {procent_garant_docx}",
58
+ f"\tclean_garant_pdf: {clean_garant_pdf}",
59
+ f"\tclean_price_doc: {clean_price_doc}",
60
+ f"\tclean_garant_docx: {clean_garant_docx}", sep="\n")
61
+
62
+ if (
63
+ abs(clean_garant_pdf - procent_garant_docx) < 3 and
64
+ abs(clean_price_doc - procent_garant_docx) < 3):
65
+ # ( abs(clean_garant_pdf - procent_garant_docx) < 3 and
66
+ # clean_price_doc == None):
67
+ # print(colored("ВЕРНО", 'green'))
68
+ st.write(":green[ВЕРНО]")
69
+ # st.write("ВЕРНО")
70
+ correct = True
71
+ # """
72
+ # случай 3
73
+ # """
74
+ elif garant_pdf and garant_docx and all([
75
+ "Российский рубль" in garant_pdf,
76
+ "%" in garant_docx,
77
+ price_doc == None
78
+ ]):
79
+ clean_garant_pdf = float(garant_pdf.removesuffix("Российский рубль").strip())
80
+ clean_garant_docx = garant_docx[0].replace(" ", '').replace("процент", "%")
81
+ for MCK in MCKs:
82
+ procent_garant_docx = float(garant_docx.strip("% ")) * MCK / 100
83
+ print(
84
+ "СРАВНЕНИЕ\n" +
85
+ f"\tprocent_garant_docx: {procent_garant_docx}\n" +
86
+ f"\tclean_garant_pdf: {clean_garant_pdf}\n")
87
+ if abs(clean_garant_pdf - procent_garant_docx) < 3:
88
+ # print(colored("ВЕРНО", 'green'))
89
+ st.write(":green[ВЕРНО]")
90
+ # st.write("ВЕРНО")
91
+ correct = True
92
+
93
+ if not correct:
94
+ # print(colored("ERROR Требуется проверка", 'magenta'))
95
+ st.write(":red[ОШИБКА]")
96
+ # st.write("ERROR Требуется проверка")
97
+ st.write("Проверьте блок обеспечения гарантийных обязательств на совпадение требований Извещения и проекта Контракта,"
98
+ " а также арифметические операции")
99
+ st.write("Условие Извещения (Российский рубль) = Условие ПК % * НМЦК")
100
+ st.write("Условие Извещения (Российский рубль) = Условие ПК (рублей)")
101
+ st.write("Условие Извещения 'не требуется' = Условие ПК 'не установлено'")
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
helpers.py ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from operator import itemgetter
2
+ import re
3
+ from bs4 import BeautifulSoup
4
+ from termcolor import colored
5
+
6
+
7
+ def get_pdf_blocks(pdf_doc):
8
+ all_blocks = []
9
+ for page_num, page in enumerate(pdf_doc):
10
+ page_blocks = page.get_text("blocks")
11
+ page_blocks = [(round(el[0]),
12
+ round(el[1]),
13
+ round(el[2]),
14
+ round(el[3]),
15
+ el[4].strip()) for el in page_blocks if el[-1] == 0]
16
+ page_blocks.sort(key=itemgetter(1, 0))
17
+ all_blocks += page_blocks
18
+ all_blocks = [el[-1] for el in all_blocks]
19
+ all_blocks = [
20
+ string.replace(u'\xa0', u' ') for string in all_blocks
21
+ ]
22
+ all_blocks = [
23
+ re.sub("\s+", " ", block) for block in all_blocks
24
+ ]
25
+ return all_blocks
26
+
27
+
28
+ def get_doc_blocks(doc):
29
+ paragraphs = []
30
+ for doc_para in doc.paragraphs:
31
+ if doc_para.text:
32
+ paragraphs.append(doc_para.text)
33
+ else:
34
+ soup = BeautifulSoup(doc_para._p.xml)
35
+ paragraphs += [
36
+ j.strip() for j in
37
+ soup.find_all("w:p")[0].text.strip().split("\n\n")
38
+ if j.strip()
39
+ ]
40
+ paragraphs = [
41
+ string.replace(u'\xa0', u' ') for string in paragraphs
42
+ ]
43
+ paragraphs = [
44
+ re.sub("\s+", " ", block) for block in paragraphs
45
+ ]
46
+ return paragraphs
47
+
48
+
49
+ pdf_oik_regex = [
50
+ "\d+(?:\.\d{2})?%",
51
+ "\d+(?:\.\d{2})? Российский рубль",
52
+ "((?:не требуется)|(?:не установлены))",
53
+ ]
54
+
55
+
56
+ def parse_pdf_oik(all_blocks, debug_print=False):
57
+ oik_pdf = None
58
+ check_if_3_30_present, check_if_24_22_present = False, False
59
+
60
+ for i, block in enumerate(all_blocks):
61
+ if "ч. 3 ст. 30" in block:
62
+ check_if_3_30_present = True
63
+ if "ч. 24 ст. 22" in block:
64
+ check_if_24_22_present = True
65
+
66
+ for string in [
67
+ 'Размер обеспечения исполнения контракта',
68
+ 'Обеспечение исполнения контракта не требуется',
69
+ "Обеспечение исполнения контракта",
70
+ 'Размер обеспечения исполнения',
71
+ 'Размер обеспечения',
72
+ ]:
73
+ if (
74
+ not oik_pdf
75
+ and re.sub("\s", '', string.lower()) in re.sub("\s", '', block.lower())
76
+ and not re.sub("\s", '', "Размер обеспечения заявки") in re.sub("\s", '', block)
77
+ and not "гарантийных" in block
78
+ ):
79
+ if debug_print:
80
+ print("CAND_STRING", block)
81
+
82
+ # print(string)
83
+ for possible_value in pdf_oik_regex:
84
+ if oik_pdf := re.findall(possible_value, block):
85
+ if debug_print:
86
+ print("BLOCK_FOUND", block)
87
+
88
+ break
89
+ elif oik_pdf := re.findall(possible_value, all_blocks[i + 1]):
90
+ if debug_print:
91
+ print("BLOCK_FOUND", block)
92
+
93
+ break
94
+ elif oik_pdf := re.findall(possible_value, all_blocks[i + 2]):
95
+ if debug_print:
96
+ print("BLOCK_FOUND", block)
97
+
98
+ break
99
+
100
+ return oik_pdf, check_if_3_30_present, check_if_24_22_present
101
+
102
+
103
+ oik_docx_regex = [
104
+ "(?:\d+(?:\.\d*)?|\.\d+) ?(?:процент|%)",
105
+ "(?:\d+(?:\,\d*)?|\,\d+) ?(?:процент|%)",
106
+ "\d{1,3} процент",
107
+ "не установлен(?:ы|о)",
108
+ "не устанавливается",
109
+ "\d{1,3} ?%",
110
+ "\d{1,3} ?\(десять\) ?процент",
111
+ "\d{1,3} ?\(пять\) ?процент",
112
+ "\d{1,3} ?\(тридцать\) ?процент"
113
+ ]
114
+
115
+ ot_max_znacenia_tseni_kontracta_str = "Максимальное значение цены Контракта составляет ________________, ________________ (далее – Цена Контракта)."
116
+
117
+
118
+ def parse_doc_oik(paragraphs):
119
+ oik_docx = None
120
+ ot_tseni_kontracta = False
121
+ ot_nachalnoi_tseni_kontracta = False
122
+ ot_max_znacenia_tseni_kontracta = False
123
+
124
+ for i, docpara in enumerate(paragraphs):
125
+ if ot_max_znacenia_tseni_kontracta_str in docpara:
126
+ ot_max_znacenia_tseni_kontracta = True
127
+ if any([
128
+ string in docpara.lower() for string in [
129
+ "обеспечение исполнения контракта устанавливается в размере",
130
+ "обеспечение исполнения контракта в размере",
131
+ "обеспечение исполнения настоящего контракта установлено в размере",
132
+ "обеспечение исполнения договора устанавливается в размере",
133
+ "обеспечение исполнения обязательств по настоящему контракту",
134
+ "обеспечение исполнения обязательств по контракту устанавливается в размере"
135
+ ]
136
+ ]):
137
+ for val in oik_docx_regex:
138
+ if oik_docx := re.findall(val, docpara):
139
+ print("НЕТИПОВОЙ")
140
+ print(docpara.lower())
141
+ if any([
142
+ "начальной цены контракта" in docpara.lower(),
143
+ "начальной (максимальной) цены контракта" in docpara.lower(),
144
+ "максимального значения цены контракта" in docpara.lower(),
145
+ "от начальной (макcимальной) цены контракта" in docpara.lower(),
146
+ "начальной" in docpara.lower(),
147
+ "от максимального значения цены контракта" in docpara.lower()
148
+ ]):
149
+ ot_nachalnoi_tseni_kontracta = True
150
+ elif any([
151
+ "цены контракта" in docpara.lower(),
152
+ "цены договора" in docpara.lower()
153
+ ]):
154
+ ot_tseni_kontracta = True
155
+ break
156
+ break
157
+ elif "Обеспечение исполнения Контракта" == docpara:
158
+ print(f"{paragraphs[i+1].lower() = }")
159
+ for val in oik_docx_regex:
160
+ if oik_docx := re.findall(val, paragraphs[i + 1]):
161
+ if any([
162
+ string in paragraphs[i + 1].lower() for string in [
163
+ "начальной цены контракта",
164
+ "начальной (максимальной) цены контракта",
165
+ "максимального значения цены контракта"
166
+ "начальной",
167
+ "от начальной (макcимальной) цены контракта",
168
+ "от максимального значения цены контракта"
169
+
170
+ ]
171
+ ]):
172
+ ot_nachalnoi_tseni_kontracta = True
173
+ elif "цены контракта" in paragraphs[i + 1].lower() or \
174
+ "цены договора" in paragraphs[i + 1].lower():
175
+ ot_tseni_kontracta = True
176
+ break
177
+ break
178
+
179
+ return (
180
+ oik_docx, ot_tseni_kontracta,
181
+ ot_nachalnoi_tseni_kontracta,
182
+ ot_max_znacenia_tseni_kontracta
183
+ )
184
+
185
+
186
+ fits = [
187
+ "\d{2} дней",
188
+ "\d{2} \(пятнадцати\) дней"
189
+ ]
190
+
191
+ variants = [
192
+ "возвращаются поставщику при условии надлежащего выполнения поставщиком своих обязательств по контракту в течение",
193
+ "возвращаются исполнителю при условии надлежащего выполнения исполнителем своих обязательств по контракту в течение",
194
+ "возвращаются подрядчику при условии надлежащего выполнения подрядчиком своих обязательств по контракту в течение",
195
+ "возвращаются поставщику в течение",
196
+ "в случае оказания услуги субъектом малого предпринимательства -",
197
+ "возврат обеспечения осуществляется заказчиком после подписания заключительного универсального передаточного документа в течение",
198
+ "возвращаются поставщику при условии надлежащего выполнения поставщиком своих обязательств по договору по заявлению поставщика в течение",
199
+ "возвращаются лицензиару в течение",
200
+ "возврат обеспечения осуществляется заказчиком в течение",
201
+ "возвращаются исполнителю в срок",
202
+ "возвращаются исполнителю в течение"
203
+ ]
204
+
205
+
206
+ def parse_doc_days(paragraphs):
207
+ days_docx = None
208
+ for i, docpara in enumerate(paragraphs):
209
+ if any([
210
+ variant in docpara.lower() for variant in variants
211
+ ]):
212
+ for val in fits:
213
+ if days_docx := re.findall(val, docpara):
214
+ break
215
+ pass
216
+ if days_docx:
217
+ # print("days_docx", days_docx)
218
+ days_docx = days_docx[0]
219
+ for possible_repl in [" (пятнадцати) дней", "дней"]:
220
+ days_docx = days_docx.replace(possible_repl, "").strip()
221
+
222
+ days_docx = int(days_docx)
223
+ # print("corrected days_docx", days_docx)
224
+ return days_docx
225
+
226
+
227
+ price_rub_regex = [
228
+ "\d+(?:\.\d{2})? руб.",
229
+ "\d+(?:\.\d{2})? рублей",
230
+ "\d+(?:\,\d{2})? рублей",
231
+ "\d+(?:\,\d{2})? руб",
232
+ "\d+(?:\.\d{2})? Российский рубль",
233
+ "((?:\d{1,3})(?:(?:\s\d{1,3})+)),(\d\d)",
234
+ "((?:\d{1,3})(?:(?:.\d{1,3})+))\.(\d\d)"
235
+ ]
236
+
237
+
238
+ def check_percent_before_price(paragraphs):
239
+ for i, docpara in enumerate(paragraphs):
240
+ if any([
241
+ re.sub("\s", '', string) in re.sub("\s", '', docpara.lower())
242
+ for string in [
243
+ 'от цены контракта',
244
+ 'от начальной (максимальной) цены контракта'
245
+ ]
246
+ ]):
247
+ for rub_re in price_rub_regex:
248
+ if re.findall(rub_re, docpara):
249
+ if temp := re.search(rub_re, docpara):
250
+ if docpara.find("%") != -1 and docpara.find("%") < temp.span()[0]:
251
+ print(colored("Ошибка, указана цена после %!!!", 'red'))
252
+ print(f"\t{docpara = }")
253
+ print("-"*50)
254
+ return True
255
+ return False
256
+
257
+
258
+ rub_regex = [
259
+ "\d+(?:\.\d{2})? руб.",
260
+ "\d+(?:\.\d{2})? рублей",
261
+ "\d+(?:\,\d{2})? рублей",
262
+ "\d+(?:\,\d{2})? руб",
263
+ "\d+(?:\.\d{2})? Российский рубль"
264
+ ]
265
+
266
+
267
+ def get_mck(all_blocks,debug_print=False):
268
+ MCK = []
269
+ for i, block in enumerate(all_blocks):
270
+ if re.sub("\s", '', 'Начальная (максимальная) цена контракта') \
271
+ in re.sub("\s", '', block):
272
+ if debug_print:
273
+ print("MCK_TEXT", all_blocks[i+1])
274
+ print("MCK_TEXT", block)
275
+ print("-"*70)
276
+ for rub_re in rub_regex:
277
+ MCK += re.findall(rub_re, all_blocks[i+1])
278
+ MCK += re.findall(rub_re, block)
279
+
280
+ elif re.sub("\s", '', 'Максимальное значение цены контракта') \
281
+ in re.sub("\s", '', block):
282
+ for rub_re in rub_regex:
283
+ if debug_print:
284
+ print("MCK_TEXT", all_blocks[i+1])
285
+ print("MCK_TEXT", block)
286
+ print("-"*70)
287
+ MCK += re.findall(rub_re, all_blocks[i+1])
288
+ MCK += re.findall(rub_re, block)
289
+ return [
290
+ float(re.sub("[а-яА-Я]", '', el).replace(",", ".").strip())
291
+ for el in MCK
292
+ ]
ikz.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from docx import Document
3
+ from helpers import get_doc_blocks
4
+
5
+ def get_ikz_pdf(pdf_blocks):
6
+ ikz_pdf = set()
7
+ for block in pdf_blocks:
8
+ ikz_pdf.update(
9
+ re.findall("\d{32,40}", block)
10
+ )
11
+ return ikz_pdf
12
+
13
+
14
+ def get_ikz_doc(doc):
15
+ ikz_docx = set()
16
+ paragraphs = get_doc_blocks(doc)
17
+ ikz_doc_regex = ["\d{36}", "(?:\d{2})(?:-\d{3,20}){5}"]
18
+
19
+ for docpara in paragraphs:
20
+ for val in ikz_doc_regex:
21
+ ikz_docx.update(
22
+ re.findall(val, docpara)
23
+ )
24
+ for table in doc.tables:
25
+ for row in table.rows:
26
+ for cell in row.cells:
27
+ for para in cell.paragraphs:
28
+ for val in ikz_doc_regex:
29
+ ikz_docx.update(
30
+ re.findall(val, para.text)
31
+ )
32
+ return ikz_docx
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ PyMuPDF==1.23.5
2
+ docx==0.2.4
3
+ termcolor==2.3.0
4
+ python-docx==1.0.1
5
+ BeautifulSoup4==4.12.2
6
+ htbuilder==0.6.2
7
+
8
+