"""act_date — дата акта об изъятии, а не первой попавшейся ссылки (#2464). `_extract_act_date` брал ПЕРВОЕ «от DD.MM.YYYY» во всём OCR-тексте. «Сообщение о планируемом изъятии» открывается списком оснований, и первой строкой там почти всегда стоит «Решение Екатеринбургской городской Думы от 06.07.2004 № 60/1 «Об утверждении Генерального плана города»» — то есть Генплан, а не акт об изъятии. На проде это дало 11 строк из 27 (два РАЗНЫХ документа: развязка на Сибирском тракте и улица Энергостроителей) с одной датой 2004-07-06 при проектах 2020 и 2022 годов. Проверено не по догадке: все пять исходных PDF были загружены и распознаны тем же трактом, что использует загрузчик (`ocr_pdf_text` в прод-контейнере). Тексты цитат ниже — дословно оттуда, включая перемешивание колонок OCR'ом. Правило («постановлени» в 120 символах перед датой) откалибровано на всех пяти документах сразу, а не на одном: окна 80/120/160 дают одинаковые 5 из 5. Более узкий вариант (плюс «администраци») давал те же 5 из 5, но ломал законный случай «Постановление № 509-ПП» — областной акт без слова «администрация», уже закреплённый тестом test_act_date_extracted_from_text. Взято широкое условие. Патченный код прогнан по всем пяти распознанным текстам целиком: 27 записей — ровно столько же, сколько строк в land_reservation, из них 11 меняют дату 2004-07-06 на настоящую, 16 остаются прежними. """ from __future__ import annotations from app.services.scrapers.izyatie_ocr import _extract_act_date, extract_izyatie_records # Заголовок раздела — дословно с прода (basis_act в land_reservation). ЗАГОЛОВОК = ( "Сообщение о планируемом изъятии земельных участков и объектов недвижимого " "имущества для муниципальных нужд" ) КАД = "66:41:0303004:22" def _дата_записи(текст_документа: str) -> str | None: """act_date так, как её увидит land_reservation — через сквозной путь. Зовём `extract_izyatie_records`, а не приватный хелпер: его сигнатура одинакова на обеих сторонах, поэтому против origin/main тест краснеет НЕВЕРНЫМ ЗНАЧЕНИЕМ (дата Генплана), а не TypeError из-за нового параметра. """ записи = extract_izyatie_records(f"{текст_документа}\n{КАД}", ЗАГОЛОВОК, "http://x/y") assert записи, "кад-номер не разобран — тест смотрел бы не туда" return записи[0]["act_date"] # ── Дословные фрагменты OCR прод-документов ─────────────────────────────────── # 89adb28a… — развязка Базовый/Комсомольская/Сибирский тракт. На проде дал 2004-07-06. ДОК_РАЗВЯЗКА = ( "Администрация города Екатеринбурга\n\n" "— Решение Екатеринбургской городской Думы от\n06.07.2004 № 60/1 «Об утверждении\n" "Генерального плана развития городского округа»;\n\n" "— Приказ Министерства строительства и развития\nинфраструктуры Свердловской области от\n" "30.12.2021 № 746-П;\n\n" "— Постановление Администрации города\nЕкатеринбурга от 27.05.2022 № 1413\n" "«Об утверждении проекта планировки и проекта межевания территории»" ) # 9b9d9a99… — улица Энергостроителей. На проде тоже дал 2004-07-06. ДОК_ЭНЕРГОСТРОИТЕЛЕЙ = ( "Администрация города Екатеринбурга\n\n" "— Решение Екатеринбургской городской Думы от\n06.07.2004 № 60/1 «Об утверждении\n" "Генерального плана развития городского округа»;\n\n" "— Приказ Министерства строительства и развития\nинфраструктуры Свердловской области от\n" "30.12.2021 № 746-П «О внесении изменений в Генеральный план на период до 2025 года»;\n\n" "— Постановление Администрации города\nЕкатеринбурга от 12.02.2020 № 259 «Об утверждении\n" "проекта планировки и проекта межевания территории»" ) # bf2bb1bd… — OCR перемешал колонки таблицы: слова фразы идут вперемешку. ДОК_ПЕРЕМЕШАННЫЙ = ( "Постановление Администрации города утверждении проекта планировки\n" "Екатеринбурга от 29.09.2015 № 2687 территории и проекта межевания\n" "«Об утверждении» (в ред. Постановления Администрации города\n" "Екатеринбурга от 14.07.2022 № 1995)" ) # ccd00215… — то же перемешивание, но короче. ДОК_ПЕРЕМЕШАННЫЙ_2 = ( "Реквизиты документов (при наличии таких Постановление Администрации города\n" "документами) Екатеринбурга от 19.04.2019 № 863 «Об\nутверждении проекта межевания территории»" ) # 188a5c36… — первой же датой идёт нужное постановление. ДОК_ПРЯМОЙ = ( "Реквизиты документов (при наличии таких документами)\n" "Постановление Администрации города Екатеринбурга от 24.06.2019 № 1504\n" "«Об утверждении проекта планировки и проекта межевания территории»" ) def test_genplan_citation_is_not_taken_as_act_date() -> None: """Головной: дата Генплана-2004 не должна становиться датой изъятия. На origin/main возвращается '2004-07-06' — дата чужого документа, на 18 лет раньше настоящего основания. """ got = _дата_записи(ДОК_РАЗВЯЗКА) assert got != "2004-07-06", "взята дата Решения Думы об утверждении Генерального плана" assert got == "2022-05-27", f"ожидали дату постановления № 1413, получили {got!r}" def test_second_document_with_same_genplan_citation() -> None: """Тот же дефект во втором документе — он и дал одинаковую дату у 11 строк.""" got = _дата_записи(ДОК_ЭНЕРГОСТРОИТЕЛЕЙ) assert got == "2020-02-12", f"ожидали дату постановления № 259, получили {got!r}" def test_ministry_order_is_not_taken_either() -> None: """Контроль: приказ Министерства между Генпланом и постановлением тоже не берётся.""" got = _дата_записи(ДОК_РАЗВЯЗКА) assert got != "2021-12-30", "взята дата приказа Министерства строительства" def test_ocr_column_scramble_still_resolves() -> None: """Контроль ширины окна: перемешанные OCR'ом колонки не должны ломать разбор. Окно шире самой фразы (~50 символов) именно ради этих двух документов: между «Постановление» и «от DD.MM.YYYY» вклинивается текст соседней колонки. """ assert _дата_записи(ДОК_ПЕРЕМЕШАННЫЙ) == "2015-09-29" assert _дата_записи(ДОК_ПЕРЕМЕШАННЫЙ_2) == "2019-04-19" def test_correct_documents_unchanged() -> None: """Контроль от переусердствования: там, где на проде было верно, ничего не меняется.""" assert _дата_записи(ДОК_ПРЯМОЙ) == "2019-06-24" def test_no_act_citation_gives_none_not_a_wrong_date() -> None: """Контроль: без основания — None, а не дата постороннего документа. Отсутствие даты честнее: по чужой дате нельзя ни отфильтровать актуальные изъятия, ни сверить срок, и она неотличима от настоящей. """ текст = "Решение Екатеринбургской городской Думы от 06.07.2004 № 60/1 «Об утверждении»" assert _дата_записи(текст) is None def test_title_path_does_not_require_context() -> None: """Контроль: у заголовка ссылок на чужие акты нет, там правило не применяется.""" assert _extract_act_date("Постановление от 27.05.2022 № 1413") == "2022-05-27"