fix(#237): «76-исключения», разнесение по стороне строки и по периметру (AURORA-2034) #238
@ -100,17 +100,23 @@ def distribute_vgo_rows(data: DistributionInput) -> Distribution:
|
||||
for row in data.rows:
|
||||
if not used.isdisjoint(row.entry_ids):
|
||||
continue
|
||||
manual = row.entry_ids in data.manual_keys
|
||||
# §5 п. 2a: разносятся только строки между разными компаниями периметра; строка с контрагентом вне периметра
|
||||
# или «сам на себя» в таблицу не попадает, если по ней нет ручного решения аналитика (AURORA-2034)
|
||||
in_perimeter = (
|
||||
row.legal_entity_id in data.members
|
||||
and row.counterparty_id in data.members
|
||||
and row.legal_entity_id != row.counterparty_id
|
||||
)
|
||||
if not manual and not in_perimeter:
|
||||
continue
|
||||
rule_ids = rules_for(data.owners, row.account_id, row_side(row.closing_debit, row.closing_credit))
|
||||
if (
|
||||
row.entry_ids not in data.manual_keys
|
||||
not manual
|
||||
and len(rule_ids) == 1
|
||||
and (
|
||||
row.legal_entity_id in data.members
|
||||
and row.counterparty_id in data.members
|
||||
and (row.closing_debit not in (None, ZERO) or row.closing_credit not in (None, ZERO))
|
||||
)
|
||||
and (row.closing_debit not in (None, ZERO) or row.closing_credit not in (None, ZERO))
|
||||
):
|
||||
auto_rules[row.entry_ids] = next(iter(rule_ids))
|
||||
elif rule_ids or row.entry_ids in data.manual_keys:
|
||||
elif rule_ids or manual:
|
||||
unassigned.add(row.entry_ids)
|
||||
return Distribution(selected, auto_rules, frozenset(unassigned), frozenset(used))
|
||||
|
||||
@ -131,6 +131,45 @@ def test_credit_row_is_matched_by_credit_side_rules_only() -> None:
|
||||
assert distribution.unassigned == {debit_row.entry_ids}
|
||||
|
||||
|
||||
def test_rows_outside_perimeter_or_to_itself_are_not_unallocated() -> None:
|
||||
"""Разносятся только строки между компаниями периметра (§5 п. 2a): контрагент вне периметра и «сам на себя»
|
||||
в нераспределённые не попадают; ручное решение аналитика по такой строке сохраняется (AURORA-2034)."""
|
||||
rule_5, rule_6, account, company_a, company_b, outsider = (uuid.uuid4() for _ in range(6))
|
||||
inside = _row(uuid.uuid4(), company_a, company_b, 1)
|
||||
outside = _row(uuid.uuid4(), company_a, outsider, 2)
|
||||
to_itself = _row(uuid.uuid4(), company_a, company_a, 3)
|
||||
to_itself_single = _row(uuid.uuid4(), company_b, company_b, 4)
|
||||
outside_manual = _row(uuid.uuid4(), company_a, outsider, 5)
|
||||
for row in (inside, outside, to_itself, to_itself_single, outside_manual):
|
||||
row.account_id = account
|
||||
owners = account_owners([(rule_5, {account}, set()), (rule_6, {account}, {account})])
|
||||
single = account_owners([(rule_6, {account}, set())])
|
||||
distribution = distribute_vgo_rows(
|
||||
DistributionInput(
|
||||
rows=[inside, outside, to_itself, outside_manual],
|
||||
exact_ids=set(),
|
||||
diff_ids=[],
|
||||
manual_keys={outside_manual.entry_ids},
|
||||
owners=owners,
|
||||
members={company_a, company_b},
|
||||
)
|
||||
)
|
||||
assert distribution.unassigned == {inside.entry_ids, outside_manual.entry_ids}
|
||||
assert distribution.auto_rules == {}
|
||||
single_distribution = distribute_vgo_rows(
|
||||
DistributionInput(
|
||||
rows=[to_itself_single],
|
||||
exact_ids=set(),
|
||||
diff_ids=[],
|
||||
manual_keys=set(),
|
||||
owners=single,
|
||||
members={company_a, company_b},
|
||||
)
|
||||
)
|
||||
assert single_distribution.auto_rules == {}
|
||||
assert single_distribution.unassigned == frozenset()
|
||||
|
||||
|
||||
async def test_unallocated_credit_row_offers_only_credit_side_rules(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Меню «Отнести к правилу» Кт-строки — только правила, где счёт на стороне кредита (AURORA-2034)."""
|
||||
version_id, company_a, company_b, rule_1, rule_2, rule_3, account = (uuid.uuid4() for _ in range(7))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user