|
import streamlit as st |
|
import fitz |
|
from io import BytesIO |
|
from termcolor import colored |
|
from docx import Document |
|
|
|
from helpers import get_mck, parse_doc_days, parse_pdf_oik, parse_doc_oik, get_pdf_blocks, get_doc_blocks, check_percent_before_price |
|
from checks import check_correctness |
|
|
|
from garant import detect_garant_pdf, detect_garant_doc, detect_garant_doc_price |
|
from garant_check import check_garant |
|
|
|
from ikz import get_ikz_pdf, get_ikz_doc |
|
|
|
from fz93 import get_fz93_doc |
|
|
|
from htbuilder import HtmlElement, div, ul, li, br, hr, a, p, img, styles, classes, fonts |
|
from htbuilder.units import percent, px |
|
from htbuilder.funcs import rgba, rgb |
|
|
|
|
|
|
|
|
|
def image(src_as_string, **style): |
|
return img(src=src_as_string, style=styles(**style)) |
|
|
|
def link(link, text, **style): |
|
return a(_href=link, _target="_blank", style=styles(**style))(text) |
|
|
|
|
|
def layout(*args): |
|
|
|
style = """ |
|
<style> |
|
# MainMenu {visibility: hidden;} |
|
footer {visibility: hidden;} |
|
.stApp { bottom: 40px; } |
|
footer: after{ |
|
content:"При возникновении вопросов по работе приложения обращайтесь в поддержку e-mail: imari.iv@mail.ru" |
|
display:block; |
|
position:relative; |
|
color:tomato; |
|
padding:5px; |
|
top:3px |
|
} |
|
</style> |
|
""" |
|
|
|
style_div = styles( |
|
|
|
left=0, |
|
bottom=0, |
|
margin=px(1, 1, 1, 1), |
|
width=percent(100), |
|
color="#FF4B4B", |
|
text_align="center", |
|
height="auto", |
|
opacity=80 |
|
|
|
) |
|
|
|
style_hr = styles( |
|
display="block", |
|
margin=px(8, 8, "auto", "auto"), |
|
border_style="inset", |
|
border_width=px(2) |
|
) |
|
|
|
body = p() |
|
foot = div( |
|
style=style_div |
|
)( |
|
hr( |
|
style=style_hr |
|
), |
|
body |
|
) |
|
|
|
st.markdown(style, unsafe_allow_html=True) |
|
|
|
for arg in args: |
|
if isinstance(arg, str): |
|
body(arg) |
|
|
|
elif isinstance(arg, HtmlElement): |
|
body(arg) |
|
|
|
st.markdown(str(foot), unsafe_allow_html=True) |
|
|
|
|
|
def footer(): |
|
myargs = [ |
|
"При возникновении вопросов по работе приложения обращайтесь в поддержку ", |
|
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)), |
|
" @Imari_Iv ", br(), |
|
|
|
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)), |
|
|
|
|
|
|
|
br(), |
|
|
|
] |
|
layout(*myargs) |
|
|
|
def main(): |
|
st.title("Закупочный Патруль") |
|
|
|
|
|
pdf_files = st.file_uploader("Загрузите PDF Извещения", type=["pdf"], accept_multiple_files=True) |
|
for pdf_file in pdf_files: |
|
bytes_data = pdf_file.read() |
|
pdf_doc = fitz.open(stream=bytes_data, filetype="pdf") |
|
st.write("Файл Извещения:", pdf_file.name) |
|
|
|
|
|
|
|
docx_files = st.file_uploader("Загрузите DOCX файл ПК", type=["docx"], accept_multiple_files=True) |
|
for docx_file in docx_files: |
|
doc_bytes = docx_file.read() |
|
doc = Document(BytesIO(doc_bytes)) |
|
|
|
st.write("файл ПК:", docx_file.name) |
|
|
|
|
|
|
|
if st.button("Проверить", type="primary"): |
|
if pdf_file is not None and docx_file is not None: |
|
|
|
print("=" * 80) |
|
st.write("_" * 80) |
|
""" |
|
ЧАСТЬ 1 "Обеспечение исполнения контракта" |
|
""" |
|
|
|
|
|
try: |
|
paragraphs = get_doc_blocks(doc) |
|
pdf_blocks = get_pdf_blocks(pdf_doc) |
|
|
|
percent_before_price = check_percent_before_price(paragraphs) |
|
|
|
( |
|
oik_pdf, |
|
check_if_3_30_present, |
|
check_if_24_22_present |
|
) = parse_pdf_oik(pdf_blocks, debug_print=False) |
|
|
|
print(f"{check_if_3_30_present = }\n{check_if_24_22_present = }") |
|
( |
|
oik_docx, |
|
ot_tseni_kontracta, |
|
ot_nachalnoi_tseni_kontracta, |
|
ot_max_znacenia_tseni_kontracta |
|
) = parse_doc_oik(paragraphs) |
|
if oik_docx: |
|
clean_oik_docx = ( |
|
oik_docx[0] |
|
.replace(" процент", "%") |
|
.replace(" %", '%') |
|
) |
|
else: |
|
clean_oik_docx = "" |
|
if oik_pdf: |
|
clean_oik_pdf = oik_pdf[0] |
|
else: |
|
clean_oik_pdf = "" |
|
|
|
MCKs = get_mck(pdf_blocks) |
|
clean_days_docx = parse_doc_days(paragraphs) |
|
print(f"{clean_oik_docx = }\n{clean_oik_pdf = }") |
|
|
|
except Exception as ex: |
|
|
|
st.write(f"ERROR при прочтении {ex}") |
|
|
|
clean_days_docx, MCKs, clean_oik_pdf, clean_oik_doсx = None, None, None, None |
|
try: |
|
if MCKs is None: |
|
pass |
|
elif len(MCKs) >= 1: |
|
if len(MCKs) > 1: |
|
print("MCK Не один") |
|
check_correctness( |
|
check_if_3_30_present=check_if_3_30_present, |
|
check_if_24_22_present=check_if_24_22_present, |
|
ot_max_znacenia_tseni_kontracta=ot_max_znacenia_tseni_kontracta, |
|
clean_oik_pdf=clean_oik_pdf, |
|
clean_oik_docx=clean_oik_docx, |
|
ot_nachalnoi_tseni_kontracta=ot_nachalnoi_tseni_kontracta, |
|
ot_tseni_kontracta=ot_tseni_kontracta, |
|
MCKs=MCKs, |
|
clean_days_docx=clean_days_docx, |
|
percent_before_price=percent_before_price, |
|
) |
|
else: |
|
print("MCK отсутствует!") |
|
|
|
except Exception as ex: |
|
|
|
|
|
st.write(f"ERROR при сравнении {ex}") |
|
|
|
print("=" * 80) |
|
st.write("_" * 80) |
|
""" |
|
ЧАСТЬ 2 "Обеспечение гарантийных обязательств" |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
paragraphs = get_doc_blocks(doc) |
|
pdf_blocks = get_pdf_blocks(pdf_doc) |
|
|
|
try: |
|
garant_pdf = detect_garant_pdf(pdf_blocks, debug_print=False) |
|
garant_docx = detect_garant_doc(paragraphs, debug_print=False) |
|
|
|
MCKs = get_mck(pdf_blocks, debug_print=False) |
|
price_doc = detect_garant_doc_price(paragraphs, debug_print=False) |
|
|
|
|
|
except Exception as ex: |
|
|
|
st.write(f":red[ERROR при прочтении ЧАСТЬ 2, {ex}]") |
|
|
|
check_garant( |
|
garant_pdf=garant_pdf, |
|
garant_docx=garant_docx, |
|
price_doc=price_doc, |
|
MCKs=MCKs |
|
) |
|
print("=" * 80) |
|
st.write("_" * 80) |
|
""" |
|
ЧАСТЬ 3 "ИКЗ" |
|
""" |
|
|
|
ikz_pdf = get_ikz_pdf(pdf_blocks) |
|
ikz_docx = get_ikz_doc(doc) |
|
if ikz_docx and ikz_pdf: |
|
ikz_docx_clean = set( |
|
[el.replace("-", '') for el in ikz_docx] |
|
) |
|
ikz_pdf_clean = set( |
|
[el.replace("-", '') for el in ikz_pdf] |
|
) |
|
if ikz_docx_clean == ikz_pdf_clean: |
|
|
|
st.write(":green[РАВНЫ]") |
|
|
|
else: |
|
|
|
st.write(":red[ОШИБКА]") |
|
|
|
for el in sorted(ikz_docx_clean): |
|
if el not in ikz_pdf_clean: |
|
|
|
st.write(f"ИКЗ {el} присутствует в .docx, но не в .pdf") |
|
print("-" * 60) |
|
st.write("-" * 60) |
|
for el in sorted(ikz_pdf_clean): |
|
if el not in ikz_docx_clean: |
|
|
|
st.write(f"ИКЗ {el} присутствует в .pdf, но не в .docx") |
|
else: |
|
|
|
st.write(":red[ПУСТОЕ ЗНАЧЕНИЕ]") |
|
|
|
|
|
print("=" * 80) |
|
st.write("_" * 80) |
|
""" |
|
ЧАСТЬ 4 "часть 1 статьи 93 ФЗ-44 в ПК" |
|
""" |
|
|
|
fz93_docx = get_fz93_doc(doc) |
|
if fz93_docx: |
|
print(colored("ОШИБКА", 'magenta')) |
|
st.write(":red[ОШИБКА]") |
|
print("ч. 1 ст. 93 ФЗ в ПК") |
|
st.write("ч. 1 ст. 93 ФЗ в ПК") |
|
else: |
|
print(colored("ВЕРНО", 'green')) |
|
st.write(":green[ВЕРНО]") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.header(':blue[ККП МО]:arrow_upper_right:',anchor=None, divider="blue") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if "text_widget" not in st.session_state: |
|
st.session_state.text_widget = False |
|
|
|
|
|
if st.button("i"): |
|
st.session_state.text_widget = not st.session_state.text_widget |
|
|
|
|
|
if st.session_state.text_widget: |
|
container = st.container(border=True) |
|
container.write("**Руководство пользователя**") |
|
container.write(" :white_check_mark: Для проверки вашей закупочной документации поместите в " |
|
"первый слот проект Извещения в формате PDF, во второй слот добавьте проект " |
|
"Контракта в формате DOCX.") |
|
container.write(" :green[Ваш документ не должен быть создан в версии Microsoft Word 97–2003 (.doc)] ") |
|
container.write(" :white_check_mark: Нажмите кнопку :red[Проверить] ") |
|
container.write(" :white_check_mark: Посмотрите на результаты проверки блоков закупочной документации. " |
|
" Если ответ :green[ВЕРНО] или :green[РАВНЫ], значит ошибок не обнаружено.") |
|
container.write( " :white_check_mark: В случае получения результата :red[ОШИБКА] проверьте соответсвующий блок вашей документации.") |
|
|
|
|
|
|
|
container.write(":blue[ЧАСТЬ 1 ]") |
|
container.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части" |
|
" 'Обеспечения исполнения Контракта'.") |
|
|
|
container.write("В случае получения результата :red[ОШИБКА]") |
|
|
|
container.write( " :red[ 1. Если Обеспечение исполнения Контракта указано в Приложении к проекту Контракта проверьте его самостоятельно и проигнорируйте сообщение об ошибке]") |
|
container.write( " 2. Проверьте ваш документ в соответствии с появившейся инструкцией.") |
|
container.write( " 3. Не забудьте проверить корректность вычислений.") |
|
container.write("В случае получения результата :red[ОШИБКА в днях OIK], проверьте правильность срока возврата обеспечения.") |
|
container.write("В случае получения результата :red[ERROR при прочтении, пожалуйста проверьте документ!] или " |
|
" :red[ERROR при сравнении] - проверьте наличие данного блока в вашей документации.") |
|
|
|
|
|
container.write(":blue[ЧАСТЬ 2 ]") |
|
container.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части" |
|
" 'Обеспечения гарантийных обязательств'.") |
|
container.write("В случае получения результата :red[ОШИБКА], проверьте данный блок в вашем документе в соответствии с появившейся инструкцией." |
|
" Не забудьте проверить корректность вычислений.") |
|
container.write("В случае получения результата :red[ERROR при прочтении ЧАСТЬ 2] " |
|
" - проверьте наличие данного блока в вашей документации.") |
|
container.write(":blue[ЧАСТЬ 3 ]") |
|
container.write("В данном блоке проверяется соответствие кодов ИКЗ в проекте Контракта с кодами Извещения в части" |
|
" 'Идентификационные коды закупки'.") |
|
container.write("В случае получения результата :red[ОШИБКА], проверьте не совпавшие коды, указанные под ним.") |
|
container.write(":blue[ЧАСТЬ 4 ]") |
|
container.write("В данном блоке проверяется отсутствие в проекте Контракта указания на часть 1 статьи 93 ФЗ-44." |
|
" В случае получения результата :red[ОШИБКА], удалите из вашего проекта Контракта данную статью.") |
|
container.write(" :white_check_mark: Если вам не удалось найти ошибку или возникли иные вопросы по работе приложения" |
|
" - обратитесь в поддержку.") |
|
container.write(":blue[Для скрытия данного блока повторно нажмите на информационную кнопку]") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
footer() |
|
|
|
|
|
|