fix(osv): нетто-признак только цепочкой нетто-строк, непрерывность периодов, спека и CLAUDE.md (AURORA-1863, AURORA-1823, #78, ревью)
I-2: в netted попадает только строка, сама сошедшаяся с детьми лишь по нетто; сошедшаяся по колонкам признак не передаёт. I-3: сальдо конца периода = сальдо начала следующего (по колонкам либо по нетто), разрыв — нарушение. M-6: сценарии спеки (защиты вложения по суммам, цепочка нетто-строк, непрерывность периодов); CLAUDE.md и докстринг checks.py ссылаются на решения владельца 28.10.2026. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e1760c08f6
commit
133b31a1f3
@ -79,11 +79,13 @@ CORS, регистрация SMB-сессии, импорт `raisa_fastapi_prote
|
|||||||
оракул; правятся только `make golden-update` с просмотром diff и отдельным коммитом в `fixtures`. Корректность
|
оракул; правятся только `make golden-update` с просмотром diff и отдельным коммитом в `fixtures`. Корректность
|
||||||
проверяют property-тест и ручная сверка «Итого».
|
проверяют property-тест и ручная сверка «Итого».
|
||||||
- Деньги — `Decimal`, `float` в домене нет; `needs_check` — только по контрольным суммам, структуру под сходимость не
|
- Деньги — `Decimal`, `float` в домене нет; `needs_check` — только по контрольным суммам, структуру под сходимость не
|
||||||
подгонять.
|
подгонять (решения владельца 28.10.2026 — AURORA-1858: уточнение иерархии по отступам А/Б/В с защитами, см.
|
||||||
|
`05-domain-rules.md` §1.3).
|
||||||
|
|
||||||
**Нетривиальное правило §1.4 (R-21):** при сверке «сумма детей = родитель» обороты сравниваются по колонкам, а сальдо —
|
**Нетривиальное правило §1.4 (R-21):** при сверке «сумма детей = родитель» обороты сравниваются по колонкам, а сальдо —
|
||||||
по колонкам либо по нетто `дебет − кредит`, если у родителя сальдо свёрнуто (1С показывает счёт нетто, а субсчета и
|
по колонкам либо по нетто `дебет − кредит`, если у родителя сальдо свёрнуто (1С показывает счёт нетто, а субсчета и
|
||||||
контрагентов — развёрнуто). Это решение зафиксировано в design №31; не ослаблять и не расширять без обсуждения.
|
контрагентов — развёрнуто). Это решение зафиксировано в design №31; не ослаблять и не расширять без обсуждения (решение владельца 28.10.2026, AURORA-1863: узкое нетто для
|
||||||
|
развёрнутого родителя над нетто-ребёнком — только непрерывной цепочкой нетто-строк).
|
||||||
|
|
||||||
**Счета без сальдо по аналитике (OQ-132, #11 п. 2):** список счетов (90, 91, 99) — данные `api/rules/osv_checks.yaml`, не код;
|
**Счета без сальдо по аналитике (OQ-132, #11 п. 2):** список счетов (90, 91, 99) — данные `api/rules/osv_checks.yaml`, не код;
|
||||||
тождество строки на них не проверяется, «сумма детей = родитель» (обороты всегда, сальдо — только корень → субсчета) и
|
тождество строки на них не проверяется, «сумма детей = родитель» (обороты всегда, сальдо — только корень → субсчета) и
|
||||||
|
|||||||
@ -10,12 +10,13 @@
|
|||||||
сальдо свёрнуто (не больше одной ненулевой стороны), по нетто `дебет − кредит`: 1С показывает счёт свёрнутым
|
сальдо свёрнуто (не больше одной ненулевой стороны), по нетто `дебет − кредит`: 1С показывает счёт свёрнутым
|
||||||
сальдо, а субсчета и контрагентов — развёрнутым (так во всех реальных файлах, где у счёта есть субсчета с
|
сальдо, а субсчета и контрагентов — развёрнутым (так во всех реальных файлах, где у счёта есть субсчета с
|
||||||
разными сторонами сальдо). Нетто допустимо и у развёрнутого родителя, если среди его прямых детей есть
|
разными сторонами сальдо). Нетто допустимо и у развёрнутого родителя, если среди его прямых детей есть
|
||||||
«нетто-ребёнок» — ребёнок, прошедший сверку только по нетто, или имеющий такого потомка (1С схлопнула Дт/Кт
|
«нетто-ребёнок» — ребёнок, сам сошедшийся с детьми по этой стороне сальдо (начало или конец) лишь по нетто (1С
|
||||||
субсчёта в нетто, а в родителе они остались развёрнутыми, AURORA-1863); признак идёт вверх по дереву. Развёрнутый
|
схлопнула Дт/Кт субсчёта в нетто, а в родителе они остались развёрнутыми, AURORA-1863); признак передаётся вверх
|
||||||
родитель без нетто-ребёнка сверяется по колонкам. Родитель, все дети которого — периоды («Обороты за <месяц>»,
|
только непрерывной цепочкой нетто-строк: строка, сошедшаяся по колонкам, его не передаёт. Развёрнутый родитель
|
||||||
группировка «Период», `is_period`), сверяется цепочкой: обороты = Σ оборотов периодов, сальдо начала = начало
|
без нетто-ребёнка сверяется по колонкам. Родитель, все дети которого — периоды («Обороты за <месяц>», группировка
|
||||||
первого периода, сальдо конца = конец последнего (сальдо месяцев — не слагаемые; AURORA-1823); смешанные дети —
|
«Период», `is_period`), сверяется цепочкой: обороты = Σ оборотов периодов, сальдо начала = начало первого периода,
|
||||||
обычная сумма;
|
сальдо конца = конец последнего, а конец каждого периода = начало следующего (по колонкам либо по нетто; сальдо
|
||||||
|
месяцев — не слагаемые; AURORA-1823); смешанные дети — обычная сумма;
|
||||||
3. строка «Итого» (TOTAL) = корневая строка ACCOUNT (первая строка уровня 0) либо сумма всех строк уровня 0, если их
|
3. строка «Итого» (TOTAL) = корневая строка ACCOUNT (первая строка уровня 0) либо сумма всех строк уровня 0, если их
|
||||||
несколько (лист без строки корневого счёта: верхний уровень — субсчета 58.01, 58.03; OQ-106, OQ-133; сальдо —
|
несколько (лист без строки корневого счёта: верхний уровень — субсчета 58.01, 58.03; OQ-106, OQ-133; сальдо —
|
||||||
по колонкам либо по нетто, если «Итого» свёрнуто, как у родителя в п. 2; то же для единственного корня, когда
|
по колонкам либо по нетто, если «Итого» свёрнуто, как у родителя в п. 2; то же для единственного корня, когда
|
||||||
@ -29,12 +30,15 @@
|
|||||||
аналитикой сальдо детей пусто по определению); п. 3 («Итого») не меняется.
|
аналитикой сальдо детей пусто по определению); п. 3 («Итого») не меняется.
|
||||||
|
|
||||||
Любое нарушение делает результат `needs_check` (решает оркестратор `osv.py`); парсер структуру под сходимость не
|
Любое нарушение делает результат `needs_check` (решает оркестратор `osv.py`); парсер структуру под сходимость не
|
||||||
подгоняет. Номера строк — в `OsvChecks`, причины — тексты предупреждений.
|
подгоняет (решения владельца 28.10.2026: узкое нетто для нетто-ребёнка, AURORA-1863, выше; уточнение иерархии по
|
||||||
|
отступам с защитами, AURORA-1858, `hierarchy.strategy_indent`, `05-domain-rules.md` §1.3). Номера строк — в
|
||||||
|
`OsvChecks`, причины — тексты предупреждений.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections.abc import Iterable, Sequence
|
from collections.abc import Iterable, Sequence
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from itertools import pairwise
|
||||||
|
|
||||||
from src.contract.result import OsvChecks
|
from src.contract.result import OsvChecks
|
||||||
from src.parser.classify import SUM_FIELDS, ClassifiedRow
|
from src.parser.classify import SUM_FIELDS, ClassifiedRow
|
||||||
@ -141,7 +145,8 @@ def _sums_match(
|
|||||||
with_balance: bool = True,
|
with_balance: bool = True,
|
||||||
net_child: bool = False,
|
net_child: bool = False,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Суммы родителя = Σ детей; `with_balance=False` — только обороты (сальдо детей не несёт данных)."""
|
"""Суммы родителя = Σ детей; `with_balance=False` — только обороты (сальдо детей не несёт данных). `net_child` —
|
||||||
|
среди детей есть нетто-ребёнок: сальдо (начало и конец) сверяется и по нетто."""
|
||||||
return (
|
return (
|
||||||
(not with_balance or _balance_matches(parent[_OPENING], children[_OPENING], net_child=net_child))
|
(not with_balance or _balance_matches(parent[_OPENING], children[_OPENING], net_child=net_child))
|
||||||
and not _differs(parent[_TURNOVER], children[_TURNOVER])
|
and not _differs(parent[_TURNOVER], children[_TURNOVER])
|
||||||
@ -149,9 +154,14 @@ def _sums_match(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _balance_by_net(parent: Sequence[Decimal], children: Sequence[Decimal]) -> bool:
|
def _periods_continuous(periods: Sequence[ClassifiedRow]) -> bool:
|
||||||
"""Сальдо родителя (начало или конец) не равно Σ детей по колонкам: сверка прошла только по нетто."""
|
"""Сальдо конца каждого периода = сальдо начала следующей строки периода (по колонкам либо по нетто)."""
|
||||||
return _differs(parent[_OPENING], children[_OPENING]) or _differs(parent[_CLOSING], children[_CLOSING])
|
return all(
|
||||||
|
_balance_matches(closing, opening) or _balance_matches(opening, closing)
|
||||||
|
for closing, opening in (
|
||||||
|
(_values(left)[_CLOSING], _values(right)[_OPENING]) for left, right in pairwise(periods)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _period_chain(periods: Sequence[ClassifiedRow]) -> list[Decimal]:
|
def _period_chain(periods: Sequence[ClassifiedRow]) -> list[Decimal]:
|
||||||
@ -193,19 +203,28 @@ def parent_sums(rows: Sequence[ClassifiedRow], exempt: OsvCheckRules | None = No
|
|||||||
if item.group_type == "ACCOUNT":
|
if item.group_type == "ACCOUNT":
|
||||||
has_subaccounts.add(item.parent)
|
has_subaccounts.add(item.parent)
|
||||||
violations: set[int] = set()
|
violations: set[int] = set()
|
||||||
# «Свёрнутые в нетто» строки: прошли сверку с детьми только по нетто либо имеют такого потомка. Потомки идут по
|
# Нетто-строки: строка сама сошлась с детьми по сальдо (начало или конец) лишь по нетто, по колонкам не сошлось.
|
||||||
# большим номерам строк, поэтому родители обходятся от больших номеров к меньшим.
|
# Цепочка нетто-строк непрерывна: строка, сошедшаяся по колонкам, признак вверх не передаёт. Нетто допускается на
|
||||||
|
# обеих сторонах сальдо, а не только на той, где ребёнок свёрнут: схлопнутую пару 1С не показывает ни в начале, ни
|
||||||
|
# в конце (на реальных файлах родитель расходится с детьми симметрично на обеих сторонах). Потомки идут по большим
|
||||||
|
# номерам строк, поэтому родители обходятся от больших номеров к меньшим.
|
||||||
netted: set[int] = set()
|
netted: set[int] = set()
|
||||||
for row in sorted(totals, reverse=True):
|
for row in sorted(totals, reverse=True):
|
||||||
item = by_row[row]
|
item = by_row[row]
|
||||||
with_balance = row in has_subaccounts or not _no_analytic_balance(item, exempt)
|
with_balance = row in has_subaccounts or not _no_analytic_balance(item, exempt)
|
||||||
net_child = any(child in netted for child in children_of[row])
|
net_child = any(child in netted for child in children_of[row])
|
||||||
children = totals[row]
|
children = totals[row]
|
||||||
if periods_of[row] and len(periods_of[row]) == len(children_of[row]):
|
chained = bool(periods_of[row]) and len(periods_of[row]) == len(children_of[row])
|
||||||
|
if chained:
|
||||||
children = _period_chain(periods_of[row])
|
children = _period_chain(periods_of[row])
|
||||||
if not _sums_match(_values(item), children, with_balance=with_balance, net_child=net_child):
|
if (chained and with_balance and not _periods_continuous(periods_of[row])) or not _sums_match(
|
||||||
|
_values(item), children, with_balance=with_balance, net_child=net_child
|
||||||
|
):
|
||||||
violations.add(row)
|
violations.add(row)
|
||||||
elif net_child or (with_balance and _balance_by_net(_values(item), children)):
|
elif with_balance and (
|
||||||
|
_differs(_values(item)[_OPENING], children[_OPENING])
|
||||||
|
or _differs(_values(item)[_CLOSING], children[_CLOSING])
|
||||||
|
):
|
||||||
netted.add(row)
|
netted.add(row)
|
||||||
return [row for row in by_row if row in violations]
|
return [row for row in by_row if row in violations]
|
||||||
|
|
||||||
|
|||||||
@ -229,9 +229,9 @@ def test_expanded_parent_without_netted_child_stays_violation_on_rounding_gap()
|
|||||||
assert parent_sums(rows) == [12]
|
assert parent_sums(rows) == [12]
|
||||||
|
|
||||||
|
|
||||||
def test_netted_flag_propagates_up_through_column_matched_level() -> None:
|
def test_netted_flag_does_not_pass_through_column_matched_level() -> None:
|
||||||
"""Признак «есть свёрнутый потомок» идёт вверх: счёт 11 развёрнут, субсчёт 12 сошёлся по колонкам, но над ним
|
"""Признак передаёт только строка, сама сошедшаяся с детьми по нетто (непрерывная цепочка нетто-строк): счёт 11
|
||||||
свёрнутый 13."""
|
развёрнут, субсчёт 12 сошёлся по колонкам (над свёрнутым 13) — признака у 12 нет, 11 сверяется по колонкам."""
|
||||||
rows = [
|
rows = [
|
||||||
row(11, ("300", "240", "10", "10", "300", "240"), group_type="ACCOUNT", text="60"),
|
row(11, ("300", "240", "10", "10", "300", "240"), group_type="ACCOUNT", text="60"),
|
||||||
row(12, ("130", "70", "10", "10", "130", "70"), level=1, parent=11, group_type="ACCOUNT"),
|
row(12, ("130", "70", "10", "10", "130", "70"), level=1, parent=11, group_type="ACCOUNT"),
|
||||||
@ -241,6 +241,32 @@ def test_netted_flag_propagates_up_through_column_matched_level() -> None:
|
|||||||
row(16, ("70", "70", "0", "0", "70", "70"), level=2, parent=12, group_type="ACCOUNT"),
|
row(16, ("70", "70", "0", "0", "70", "70"), level=2, parent=12, group_type="ACCOUNT"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
assert parent_sums(rows) == [11]
|
||||||
|
|
||||||
|
|
||||||
|
def test_netted_flag_continues_through_chain_of_net_rows() -> None:
|
||||||
|
"""Цепочка нетто-строк: 12 сошёлся с 13 по нетто, 11 над ним — тоже по нетто."""
|
||||||
|
rows = [
|
||||||
|
row(11, ("260", "200", "10", "10", "260", "200"), group_type="ACCOUNT", text="60"),
|
||||||
|
row(12, ("130", "70", "10", "10", "130", "70"), level=1, parent=11, group_type="ACCOUNT"),
|
||||||
|
row(13, ("60", None, "10", "10", "60", None), level=2, parent=12, group_type="ACCOUNT"),
|
||||||
|
row(14, ("90", None, "10", None, "90", None), level=3, parent=13, group_type="ACCOUNT"),
|
||||||
|
row(15, (None, "30", None, "10", None, "30"), level=3, parent=13, group_type="ACCOUNT"),
|
||||||
|
]
|
||||||
|
|
||||||
|
assert parent_sums(rows) == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_net_child_allows_net_on_both_balance_sides() -> None:
|
||||||
|
"""R-9: ребёнок свёрнут в нетто по сальдо начала (на конец сошёлся по колонкам), а развёрнутый родитель на конец
|
||||||
|
расходится с ним симметрично: схлопнутую пару 1С не показывает ни в начале, ни в конце — нетто на обе стороны."""
|
||||||
|
rows = [
|
||||||
|
row(12, ("130", "70", "10", "10", "130", "70"), group_type="ACCOUNT"),
|
||||||
|
row(13, ("60", None, "10", "10", "60", None), level=1, parent=12, group_type="ACCOUNT"),
|
||||||
|
row(14, ("90", None, "10", None, "60", None), level=2, parent=13, group_type="ACCOUNT"),
|
||||||
|
row(15, (None, "30", None, "10", None, None), level=2, parent=13, group_type="ACCOUNT"),
|
||||||
|
]
|
||||||
|
|
||||||
assert parent_sums(rows) == []
|
assert parent_sums(rows) == []
|
||||||
|
|
||||||
|
|
||||||
@ -274,6 +300,40 @@ def test_period_children_chain_violations(broken: dict[str, str]) -> None:
|
|||||||
assert parent_sums(period_tree(**broken)) == [12]
|
assert parent_sums(period_tree(**broken)) == [12]
|
||||||
|
|
||||||
|
|
||||||
|
def test_period_chain_gap_in_the_middle_is_violation() -> None:
|
||||||
|
"""Начало и конец цепочки, обороты сходятся, но сальдо конца месяца ≠ сальдо начала следующего (90 → 95)."""
|
||||||
|
rows = [
|
||||||
|
row(12, ("100", None, None, "30", "70", None), level=2, parent=10, group_type="COUNTERPARTY"),
|
||||||
|
row(13, ("100", None, None, "10", "90", None), level=3, parent=12, group_type="OTHER", is_period=True),
|
||||||
|
row(14, ("95", None, None, "10", "85", None), level=3, parent=12, group_type="OTHER", is_period=True),
|
||||||
|
row(15, ("85", None, None, "10", "70", None), level=3, parent=12, group_type="OTHER", is_period=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
assert parent_sums(rows) == [12]
|
||||||
|
|
||||||
|
|
||||||
|
def test_period_chain_may_skip_months_but_must_be_continuous() -> None:
|
||||||
|
"""Пропуск месяцев без строк допустим: сравниваются соседние строки периодов."""
|
||||||
|
rows = [
|
||||||
|
row(12, ("100", None, None, "30", "70", None), level=2, parent=10, group_type="COUNTERPARTY"),
|
||||||
|
row(13, ("100", None, None, "10", "90", None), level=3, parent=12, group_type="OTHER", is_period=True),
|
||||||
|
row(14, ("90", None, None, "20", "70", None), level=3, parent=12, group_type="OTHER", is_period=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
assert parent_sums(rows) == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_period_chain_continuity_by_net_when_one_side_is_collapsed() -> None:
|
||||||
|
"""Конец месяца развёрнут (120 Дт / 20 Кт), начало следующего свёрнуто (100 Дт): нетто совпадает."""
|
||||||
|
rows = [
|
||||||
|
row(12, ("100", None, None, "30", "70", None), level=2, parent=10, group_type="COUNTERPARTY"),
|
||||||
|
row(13, ("100", None, None, "10", "120", "20"), level=3, parent=12, group_type="OTHER", is_period=True),
|
||||||
|
row(14, ("100", None, None, "20", "70", None), level=3, parent=12, group_type="OTHER", is_period=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
assert parent_sums(rows) == []
|
||||||
|
|
||||||
|
|
||||||
def test_period_balance_is_compared_by_net_for_collapsed_parent() -> None:
|
def test_period_balance_is_compared_by_net_for_collapsed_parent() -> None:
|
||||||
"""Сальдо периодов сверяется той же функцией, что и обычное: свёрнутый родитель — по нетто."""
|
"""Сальдо периодов сверяется той же функцией, что и обычное: свёрнутый родитель — по нетто."""
|
||||||
rows = [
|
rows = [
|
||||||
|
|||||||
@ -158,9 +158,17 @@ SHALL пропускаться с предупреждением файла `SHE
|
|||||||
суммам (`100 = 60 + 40`)
|
суммам (`100 = 60 + 40`)
|
||||||
- **THEN** (а) `68.01.1` — ребёнок `68.01` (уровень +1, его аналитика глубже), если все такие пары листа на одном
|
- **THEN** (а) `68.01.1` — ребёнок `68.01` (уровень +1, его аналитика глубже), если все такие пары листа на одном
|
||||||
отступе, раскладка однозначна, а сумма детей перекладываемого родителя сходится с ним; (б) строка закрытия — ребёнок
|
отступе, раскладка однозначна, а сумма детей перекладываемого родителя сходится с ним; (б) строка закрытия — ребёнок
|
||||||
счёта; (в) внутри такого родителя строка, чьи суммы равны сумме следующих соседей, становится их родителем (жадно), но
|
счёта (оборотов не нулевые); (в) внутри такого родителя строка, чьи суммы равны сумме следующих соседей, становится
|
||||||
только если после перестройки родитель сходится, иначе дерево остаётся по отступам; родитель без нарушения не
|
их родителем (жадно, не дальше `NEST_SCAN_LIMIT` = 50 следующих соседей), но только если после перестройки родитель
|
||||||
перестраивается (равные суммы соседей `50 + 50 = 100` не делают одного ребёнком другого); листы `s47` — `done`
|
сходится, иначе дерево остаётся по отступам; родитель без нарушения не перестраивается (равные суммы соседей
|
||||||
|
`50 + 50 = 100` не делают одного ребёнком другого); листы `s47` — `done`
|
||||||
|
- Вложение по суммам (в) меняет `level` и `parent_row_number` строк в `rows[]` контракта, поэтому применяется только при
|
||||||
|
одновременном выполнении трёх защит (решение владельца 28.10.2026): (1) схема шапки не называет группы аналитики
|
||||||
|
после счёта («Субконто» без вида), то есть вложение не меняет `group_type`/`group_name` строки; (2) все прямые дети
|
||||||
|
родителя стоят на одном отступе; (3) ни вкладываемая строка, ни новый родитель не несут ИНН (колонка ИНН или хвост
|
||||||
|
названия). Иначе (шапка «Счет / Контрагенты / Договоры», контрагенты с ИНН) ошибка суммы остаётся нарушением, а лист —
|
||||||
|
`needs_check`: контрагент не становится строкой под соседом. Код без разделителя сегментов («60» и второй «60»)
|
||||||
|
по (а) не вкладывается
|
||||||
|
|
||||||
#### Scenario: Без outline и отступов
|
#### Scenario: Без outline и отступов
|
||||||
- **WHEN** разбирается синтетическая ОСВ, где уровни видны только по кодам счетов и жирности (`s03`)
|
- **WHEN** разбирается синтетическая ОСВ, где уровни видны только по кодам счетов и жирности (`s03`)
|
||||||
@ -316,9 +324,10 @@ balance_identity_violations, parent_sum_violations}`. Результат про
|
|||||||
или расхождение оборотов — нарушение
|
или расхождение оборотов — нарушение
|
||||||
|
|
||||||
#### Scenario: Развёрнутый родитель над свёрнутым в нетто ребёнком
|
#### Scenario: Развёрнутый родитель над свёрнутым в нетто ребёнком
|
||||||
- **WHEN** сальдо родителя развёрнуто (обе стороны), а среди его прямых детей есть «нетто-ребёнок» — ребёнок, прошедший
|
- **WHEN** сальдо родителя развёрнуто (обе стороны), а среди его прямых детей есть «нетто-ребёнок» — ребёнок, сам
|
||||||
сверку со своими детьми только по нетто, либо имеющий такого потомка (признак передаётся вверх по дереву), и нетто детей
|
сошедшийся со своими детьми по этой стороне сальдо (начало или конец) лишь по нетто, и нетто детей равно нетто
|
||||||
равно нетто родителя
|
родителя; признак передаётся вверх только непрерывной цепочкой нетто-строк (строка, сошедшаяся по колонкам, его не
|
||||||
|
передаёт), отдельно для начала и конца
|
||||||
- **THEN** нарушения по сальдо нет (1С схлопнула Дт/Кт субсчёта в нетто, а в родителе они остались развёрнутыми,
|
- **THEN** нарушения по сальдо нет (1С схлопнула Дт/Кт субсчёта в нетто, а в родителе они остались развёрнутыми,
|
||||||
AURORA-1863); обороты сверяются по колонкам, неверное нетто или расхождение оборотов — нарушение; развёрнутый родитель
|
AURORA-1863); обороты сверяются по колонкам, неверное нетто или расхождение оборотов — нарушение; развёрнутый родитель
|
||||||
без нетто-ребёнка по-прежнему сверяется по колонкам (расхождение даже на 0,05 при равном нетто — нарушение)
|
без нетто-ребёнка по-прежнему сверяется по колонкам (расхождение даже на 0,05 при равном нетто — нарушение)
|
||||||
@ -329,8 +338,9 @@ balance_identity_violations, parent_sum_violations}`. Результат про
|
|||||||
`is_period`)
|
`is_period`)
|
||||||
- **THEN** обороты родителя сверяются с суммой оборотов периодов, сальдо начала — с сальдо начала первого периода,
|
- **THEN** обороты родителя сверяются с суммой оборотов периодов, сальдо начала — с сальдо начала первого периода,
|
||||||
сальдо конца — с сальдо конца последнего (в порядке строк; сальдо сверяется по колонкам либо по нетто, как обычно),
|
сальдо конца — с сальдо конца последнего (в порядке строк; сальдо сверяется по колонкам либо по нетто, как обычно),
|
||||||
а не с суммой сальдо месяцев (AURORA-1823); расхождение в обороте, начале первого или конце последнего периода —
|
а не с суммой сальдо месяцев (AURORA-1823); сальдо конца каждого периода SHALL равняться сальдо начала следующей строки
|
||||||
нарушение; у родителя со смешанными детьми (периоды и обычные строки) суммы считаются как прежде
|
периода (по колонкам либо по нетто; месяцы без строк допустимы); расхождение в обороте, начале первого или конце
|
||||||
|
последнего периода либо разрыв цепочки — нарушение; у родителя со смешанными детьми (периоды и обычные строки) суммы считаются как прежде
|
||||||
|
|
||||||
#### Scenario: Счёт 91 — аналитика только с оборотами
|
#### Scenario: Счёт 91 — аналитика только с оборотами
|
||||||
- **WHEN** разбирается ОСВ по счёту 91: строки аналитики 91.01, 91.02, 91.09 несут только обороты, сальдо закрыто на
|
- **WHEN** разбирается ОСВ по счёту 91: строки аналитики 91.01, 91.02, 91.09 несут только обороты, сальдо закрыто на
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user