Upload 8 files
Browse files- app.py +412 -0
- checks.py +354 -0
- fz93.py +27 -0
- garant.py +137 -0
- garant_check.py +126 -0
- helpers.py +292 -0
- ikz.py +32 -0
- 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 |
+
#"🇷🇺", '🇷🇺'
|
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 |
+
# " with ❤️ My 🏠 is 🇷🇺 :ru: Я люблю 🇷🇺 :flag_ru: by ",
|
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 —\
|
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 |
+
|