fix(generative): устаревший VAT/office caveat в concept PDF (#2445-C1) (#2455)
This commit is contained in:
parent
c0c666cccc
commit
f3988add0a
2 changed files with 28 additions and 9 deletions
|
|
@ -66,9 +66,7 @@ def _strategy_label(strategy: str) -> str:
|
||||||
|
|
||||||
def _teap_table(variants: Sequence[ConceptVariant]) -> str:
|
def _teap_table(variants: Sequence[ConceptVariant]) -> str:
|
||||||
"""HTML-таблица ТЭП по всем вариантам (строки — показатели, колонки — стратегии)."""
|
"""HTML-таблица ТЭП по всем вариантам (строки — показатели, колонки — стратегии)."""
|
||||||
headers = "".join(
|
headers = "".join(f"<th>{html.escape(_strategy_label(v.strategy))}</th>" for v in variants)
|
||||||
f"<th>{html.escape(_strategy_label(v.strategy))}</th>" for v in variants
|
|
||||||
)
|
|
||||||
rows: list[tuple[str, list[str]]] = [
|
rows: list[tuple[str, list[str]]] = [
|
||||||
("Пятно застройки, кв.м", [_fmt_int(v.teap.built_area_sqm) for v in variants]),
|
("Пятно застройки, кв.м", [_fmt_int(v.teap.built_area_sqm) for v in variants]),
|
||||||
("Общая площадь (GFA), кв.м", [_fmt_int(v.teap.total_floor_area_sqm) for v in variants]),
|
("Общая площадь (GFA), кв.м", [_fmt_int(v.teap.total_floor_area_sqm) for v in variants]),
|
||||||
|
|
@ -107,9 +105,7 @@ def _fmt_irr(financial: FinancialModel) -> str:
|
||||||
|
|
||||||
def _financial_table(variants: Sequence[ConceptVariant]) -> str:
|
def _financial_table(variants: Sequence[ConceptVariant]) -> str:
|
||||||
"""HTML-таблица финмодели (деньги в млн руб; полный каскад + БДР + DCF)."""
|
"""HTML-таблица финмодели (деньги в млн руб; полный каскад + БДР + DCF)."""
|
||||||
headers = "".join(
|
headers = "".join(f"<th>{html.escape(_strategy_label(v.strategy))}</th>" for v in variants)
|
||||||
f"<th>{html.escape(_strategy_label(v.strategy))}</th>" for v in variants
|
|
||||||
)
|
|
||||||
rows: list[tuple[str, list[str]]] = [
|
rows: list[tuple[str, list[str]]] = [
|
||||||
(
|
(
|
||||||
"Выручка — жильё, млн руб",
|
"Выручка — жильё, млн руб",
|
||||||
|
|
@ -188,9 +184,13 @@ def _build_html(variants: Sequence[ConceptVariant]) -> str:
|
||||||
"точность метрик зависит от реального графика. Где IRR помечен «оценочный» — поток "
|
"точность метрик зависит от реального графика. Где IRR помечен «оценочный» — поток "
|
||||||
"вырожденный (нет смены знака), показан аннуализированный ROI вместо DCF-IRR. "
|
"вырожденный (нет смены знака), показан аннуализированный ROI вместо DCF-IRR. "
|
||||||
"НДС — реализация жилья и услуги застройщика по ДДУ освобождены (ст. 149 НК РФ), "
|
"НДС — реализация жилья и услуги застройщика по ДДУ освобождены (ст. 149 НК РФ), "
|
||||||
"входной НДС по СМР встроен в себестоимость; НДС начисляется только на нежилую часть "
|
"входной НДС по СМР встроен в себестоимость; НДС начисляется на нежилые части — "
|
||||||
"(машиноместа). Налог на прибыль — 25% (с 2025). Цены и себестоимость "
|
"машиноместа и коммерцию/офисы 1-го этажа (встроенный НДС в добавленной стоимости "
|
||||||
"— рыночные ориентиры. Коммерческие/офисные площади не учитываются (нет в ТЭП).</p>"
|
"каждой части). Налог на прибыль — 25% (с 2025). Цены и себестоимость — рыночные "
|
||||||
|
"ориентиры. Коммерция/офисы 1-го этажа учтены по нормативной доле от общей площади "
|
||||||
|
"и продаются с умеренной наценкой к цене жилья того же класса; себестоимость СМР "
|
||||||
|
"нежилого — по той же ставке, что и жильё (отдельной строки затрат нет, повторного "
|
||||||
|
"учёта в затратах нет).</p>"
|
||||||
"</body></html>"
|
"</body></html>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,25 @@ def test_pdf_html_build_graceful_on_empty() -> None:
|
||||||
assert "нет вариантов" in html
|
assert "нет вариантов" in html
|
||||||
|
|
||||||
|
|
||||||
|
def test_pdf_caveat_does_not_contradict_office_revenue_row() -> None:
|
||||||
|
"""Эпик #2445 C1: каскад включает нежилую выручку/НДС — caveat не должен это отрицать.
|
||||||
|
|
||||||
|
Payload — ``comfort`` (office_share=0.05 в teap.py), поэтому строка "Выручка —
|
||||||
|
нежилое (1-й этаж)" в таблице ненулевая: caveat ниже НЕ может утверждать, что
|
||||||
|
коммерция/офисы "не учитываются" или что НДС — "только машиноместа".
|
||||||
|
"""
|
||||||
|
variants = geometry.generate(_payload())
|
||||||
|
html = pdf._build_html(variants)
|
||||||
|
assert "Выручка — нежилое (1-й этаж), млн руб" in html
|
||||||
|
assert "НДС (нежилое: паркинг + коммерция), млн руб" in html
|
||||||
|
# Старые (стейл) формулировки, отрицающие модель нежилого, — не должны вернуться.
|
||||||
|
assert "не учитываются" not in html
|
||||||
|
assert "только на нежилую часть" not in html
|
||||||
|
assert "только машиноместа" not in html
|
||||||
|
# Caveat честно описывает нежилое как учтённое (не «нет в ТЭП»).
|
||||||
|
assert "нет в ТЭП" not in html
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
not _weasyprint_available(),
|
not _weasyprint_available(),
|
||||||
reason="WeasyPrint native libs unavailable on this host",
|
reason="WeasyPrint native libs unavailable on this host",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue