убраны лишние проверки
This commit is contained in:
parent
e5b998df20
commit
fb04765ae9
@ -34,11 +34,20 @@ RESULT_ERRORS: dict[int | str, dict[str, Any]] = {
|
|||||||
"description": "В плане счетов нет счетов статей результирующей таблицы",
|
"description": "В плане счетов нет счетов статей результирующей таблицы",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
PRESET_ERRORS: dict[int | str, dict[str, Any]] = {
|
||||||
|
**ERRORS,
|
||||||
|
status.HTTP_404_NOT_FOUND: {"model": ErrorDetail, "description": "Версия или правило не найдены либо недоступны"},
|
||||||
|
status.HTTP_422_UNPROCESSABLE_CONTENT: {
|
||||||
|
"model": ErrorDetail,
|
||||||
|
"description": "INVALID_RULE, RULE_REQUIRED или ACCOUNTS_REQUIRED",
|
||||||
|
},
|
||||||
|
}
|
||||||
XLSX_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
XLSX_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||||
XLSX_CONTENT: dict[int | str, dict[str, Any]] = {
|
XLSX_CONTENT: dict[int | str, dict[str, Any]] = {
|
||||||
status.HTTP_200_OK: {"content": {XLSX_MEDIA_TYPE: {"schema": {"type": "string", "format": "binary"}}}}
|
status.HTTP_200_OK: {"content": {XLSX_MEDIA_TYPE: {"schema": {"type": "string", "format": "binary"}}}}
|
||||||
}
|
}
|
||||||
EXPORT_RESPONSES = {**ERRORS, **XLSX_CONTENT}
|
EXPORT_RESPONSES = {**ERRORS, **XLSX_CONTENT}
|
||||||
|
PRESET_EXPORT_RESPONSES = {**PRESET_ERRORS, **XLSX_CONTENT}
|
||||||
RESULT_EXPORT_RESPONSES = {**RESULT_ERRORS, **XLSX_CONTENT}
|
RESULT_EXPORT_RESPONSES = {**RESULT_ERRORS, **XLSX_CONTENT}
|
||||||
|
|
||||||
|
|
||||||
@ -59,8 +68,6 @@ async def _export_response(
|
|||||||
selection: IntercompanyMatrixManualIn | None = None,
|
selection: IntercompanyMatrixManualIn | None = None,
|
||||||
) -> Response:
|
) -> Response:
|
||||||
content = await run_in_threadpool(build_matrix_workbook, matrix, info)
|
content = await run_in_threadpool(build_matrix_workbook, matrix, info)
|
||||||
if info.mode == "PRESET" and (info.rule_id is None or info.rule_no is None or info.rule_version_no is None):
|
|
||||||
raise ValueError("Для аудита PRESET нужны ID, номер и версия правила")
|
|
||||||
response = _xlsx_response(content, info.filename, ascii_fallback="intercompany-matrix.xlsx")
|
response = _xlsx_response(content, info.filename, ascii_fallback="intercompany-matrix.xlsx")
|
||||||
await audit.record(
|
await audit.record(
|
||||||
action=AuditAction.EXPORT,
|
action=AuditAction.EXPORT,
|
||||||
@ -75,11 +82,11 @@ async def _export_response(
|
|||||||
"credit_account_ids": [str(account_id) for account_id in selection.credit_account_ids] if selection else [],
|
"credit_account_ids": [str(account_id) for account_id in selection.credit_account_ids] if selection else [],
|
||||||
**(
|
**(
|
||||||
{
|
{
|
||||||
"rule_id": str(info.rule_id),
|
"rule_id": str(info.preset.id),
|
||||||
"rule_no": info.rule_no,
|
"rule_no": info.preset.rule_no,
|
||||||
"rule_version_no": info.rule_version_no,
|
"rule_version_no": info.preset.version_no,
|
||||||
}
|
}
|
||||||
if info.mode == "PRESET"
|
if info.preset is not None
|
||||||
else {}
|
else {}
|
||||||
),
|
),
|
||||||
"cells": len(matrix.cells),
|
"cells": len(matrix.cells),
|
||||||
@ -172,7 +179,7 @@ async def export_intercompany_matrix_manual(
|
|||||||
"/{version_id}/intercompany-matrix/preset/{rule_id}",
|
"/{version_id}/intercompany-matrix/preset/{rule_id}",
|
||||||
response_model=IntercompanyMatrixOut,
|
response_model=IntercompanyMatrixOut,
|
||||||
dependencies=VIEW,
|
dependencies=VIEW,
|
||||||
responses=ERRORS,
|
responses=PRESET_ERRORS,
|
||||||
summary="Рассчитать шахматку по пресету",
|
summary="Рассчитать шахматку по пресету",
|
||||||
)
|
)
|
||||||
async def build_intercompany_matrix_preset(
|
async def build_intercompany_matrix_preset(
|
||||||
@ -188,7 +195,7 @@ async def build_intercompany_matrix_preset(
|
|||||||
"/{version_id}/intercompany-matrix/preset/{rule_id}/export",
|
"/{version_id}/intercompany-matrix/preset/{rule_id}/export",
|
||||||
response_class=Response,
|
response_class=Response,
|
||||||
dependencies=VIEW,
|
dependencies=VIEW,
|
||||||
responses=EXPORT_RESPONSES,
|
responses=PRESET_EXPORT_RESPONSES,
|
||||||
summary="Скачать шахматку по пресету в XLSX",
|
summary="Скачать шахматку по пресету в XLSX",
|
||||||
)
|
)
|
||||||
async def export_intercompany_matrix_preset(
|
async def export_intercompany_matrix_preset(
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from collections import defaultdict
|
|||||||
from collections.abc import Iterable, Sequence
|
from collections.abc import Iterable, Sequence
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Literal
|
from typing import Literal, cast
|
||||||
|
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
@ -117,8 +117,21 @@ class VersionExportInfo:
|
|||||||
quarter: PeriodQuarter
|
quarter: PeriodQuarter
|
||||||
version_no: int
|
version_no: int
|
||||||
|
|
||||||
def _filename(self, prefix: str) -> str:
|
def _filename(self, prefix: str, suffix: str = "") -> str:
|
||||||
return f"{prefix}_{self.group_name}_{self.year}-{self.quarter.value}_v{self.version_no}.xlsx"
|
return f"{prefix}_{self.group_name}_{self.year}-{self.quarter.value}_v{self.version_no}{suffix}.xlsx"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class PresetRuleDetails:
|
||||||
|
id: uuid.UUID
|
||||||
|
rule_no: int
|
||||||
|
version_no: int
|
||||||
|
statement_type: StatementType
|
||||||
|
article_1_line: str
|
||||||
|
article_2_line: str
|
||||||
|
side_1: Side
|
||||||
|
debit_excluded_codes: tuple[str, ...] = ()
|
||||||
|
credit_excluded_codes: tuple[str, ...] = ()
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -127,40 +140,12 @@ class MatrixExportInfo(VersionExportInfo):
|
|||||||
debit_account_codes: tuple[str, ...]
|
debit_account_codes: tuple[str, ...]
|
||||||
credit_account_codes: tuple[str, ...]
|
credit_account_codes: tuple[str, ...]
|
||||||
measure: Measure = "closing"
|
measure: Measure = "closing"
|
||||||
rule_id: uuid.UUID | None = None
|
preset: PresetRuleDetails | None = None
|
||||||
rule_no: int | None = None
|
|
||||||
rule_version_no: int | None = None
|
|
||||||
rule_statement_type: StatementType | None = None
|
|
||||||
article_1_line: str | None = None
|
|
||||||
article_2_line: str | None = None
|
|
||||||
rule_side_1: str | None = None
|
|
||||||
debit_excluded_codes: tuple[str, ...] = ()
|
|
||||||
credit_excluded_codes: tuple[str, ...] = ()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def preset_details(self) -> tuple[StatementType, int, int, str, str]:
|
|
||||||
"""Реквизиты правила §4 для имени и шапки XLSX шахматки §6."""
|
|
||||||
details = (
|
|
||||||
self.rule_statement_type,
|
|
||||||
self.rule_no,
|
|
||||||
self.rule_version_no,
|
|
||||||
self.article_1_line,
|
|
||||||
self.article_2_line,
|
|
||||||
)
|
|
||||||
if any(value is None for value in details):
|
|
||||||
raise ValueError("Для выгрузки PRESET нужны тип, номер, версия и статьи правила")
|
|
||||||
statement_type, rule_no, rule_version_no, article_1_line, article_2_line = details
|
|
||||||
assert statement_type is not None and rule_no is not None and rule_version_no is not None
|
|
||||||
assert article_1_line is not None and article_2_line is not None
|
|
||||||
return statement_type, rule_no, rule_version_no, article_1_line, article_2_line
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filename(self) -> str:
|
def filename(self) -> str:
|
||||||
preset = ""
|
suffix = f"_rule-{self.preset.statement_type.value}-{self.preset.rule_no}" if self.preset else ""
|
||||||
if self.mode == "PRESET":
|
return self._filename("intercompany-matrix", suffix)
|
||||||
statement_type, rule_no, _, _, _ = self.preset_details
|
|
||||||
preset = f"_rule-{statement_type.value}-{rule_no}"
|
|
||||||
return f"intercompany-matrix_{self.group_name}_{self.year}-{self.quarter.value}_v{self.version_no}{preset}.xlsx"
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -725,15 +710,19 @@ class IntercompanyMatrixService:
|
|||||||
debit_account_codes=debit_codes,
|
debit_account_codes=debit_codes,
|
||||||
credit_account_codes=credit_codes,
|
credit_account_codes=credit_codes,
|
||||||
measure=result.selection.measure,
|
measure=result.selection.measure,
|
||||||
rule_id=result.rule.id if result.rule is not None else None,
|
preset=PresetRuleDetails(
|
||||||
rule_no=result.rule.rule_no if result.rule is not None else None,
|
id=result.rule.id,
|
||||||
rule_version_no=result.rule.version_no if result.rule is not None else None,
|
rule_no=result.rule.rule_no,
|
||||||
rule_statement_type=result.rule.statement_type if result.rule is not None else None,
|
version_no=result.rule.version_no,
|
||||||
article_1_line=result.rule.article_1_line if result.rule is not None else None,
|
statement_type=result.rule.statement_type,
|
||||||
article_2_line=result.rule.article_2_line if result.rule is not None else None,
|
article_1_line=result.rule.article_1_line,
|
||||||
rule_side_1=result.rule.side_1 if result.rule is not None else None,
|
article_2_line=result.rule.article_2_line,
|
||||||
debit_excluded_codes=result.selection.debit_excluded_codes,
|
side_1=cast(Side, result.rule.side_1),
|
||||||
credit_excluded_codes=result.selection.credit_excluded_codes,
|
debit_excluded_codes=result.selection.debit_excluded_codes,
|
||||||
|
credit_excluded_codes=result.selection.credit_excluded_codes,
|
||||||
|
)
|
||||||
|
if result.rule is not None
|
||||||
|
else None,
|
||||||
)
|
)
|
||||||
return result.matrix, info
|
return result.matrix, info
|
||||||
|
|
||||||
@ -778,7 +767,9 @@ class IntercompanyMatrixService:
|
|||||||
return tuple(sorted(by_id[account_id].code for account_id in ids))
|
return tuple(sorted(by_id[account_id].code for account_id in ids))
|
||||||
|
|
||||||
return MatrixSelection(
|
return MatrixSelection(
|
||||||
debit, credit, measure,
|
debit,
|
||||||
|
credit,
|
||||||
|
measure,
|
||||||
debit_rule_codes=codes(debit_ids),
|
debit_rule_codes=codes(debit_ids),
|
||||||
credit_rule_codes=codes(credit_ids),
|
credit_rule_codes=codes(credit_ids),
|
||||||
debit_excluded_codes=codes(debit_excluded),
|
debit_excluded_codes=codes(debit_excluded),
|
||||||
|
|||||||
@ -58,21 +58,21 @@ def _write_context(sheet: Worksheet, info: MatrixExportInfo) -> int:
|
|||||||
("Режим", mode_name),
|
("Режим", mode_name),
|
||||||
("Счета дебета", ", ".join(info.debit_account_codes) if info.mode != "ALL" else all_accounts),
|
("Счета дебета", ", ".join(info.debit_account_codes) if info.mode != "ALL" else all_accounts),
|
||||||
]
|
]
|
||||||
if info.mode == "PRESET" and info.debit_excluded_codes:
|
if info.preset is not None and info.preset.debit_excluded_codes:
|
||||||
extra.append(("кроме", ", ".join(info.debit_excluded_codes)))
|
extra.append(("кроме", ", ".join(info.preset.debit_excluded_codes)))
|
||||||
extra.append(("Счета кредита", ", ".join(info.credit_account_codes) if info.mode != "ALL" else all_accounts))
|
extra.append(("Счета кредита", ", ".join(info.credit_account_codes) if info.mode != "ALL" else all_accounts))
|
||||||
if info.mode == "PRESET" and info.credit_excluded_codes:
|
if info.preset is not None and info.preset.credit_excluded_codes:
|
||||||
extra.append(("кроме", ", ".join(info.credit_excluded_codes)))
|
extra.append(("кроме", ", ".join(info.preset.credit_excluded_codes)))
|
||||||
extra.append(("Показатель", "Сальдо" if info.measure == "closing" else "Оборот"))
|
extra.append(("Показатель", "Сальдо" if info.measure == "closing" else "Оборот"))
|
||||||
if info.mode == "PRESET":
|
if info.preset is not None:
|
||||||
statement_type, rule_no, rule_version_no, article_1_line, article_2_line = info.preset_details
|
preset = info.preset
|
||||||
rule_type = "ББ" if statement_type.value == "balance" else "ОФР"
|
rule_type = "ББ" if preset.statement_type.value == "balance" else "ОФР"
|
||||||
extra.extend(
|
extra.extend(
|
||||||
(
|
(
|
||||||
("Правило", f"{rule_type} № {rule_no}"),
|
("Правило", f"{rule_type} № {preset.rule_no}"),
|
||||||
("Статья А", article_1_line if info.rule_side_1 != "K" else article_2_line),
|
("Статья А", preset.article_1_line if preset.side_1 != "K" else preset.article_2_line),
|
||||||
("Статья Б", article_2_line if info.rule_side_1 != "K" else article_1_line),
|
("Статья Б", preset.article_2_line if preset.side_1 != "K" else preset.article_1_line),
|
||||||
("Версия правил", f"v{rule_version_no}"),
|
("Версия правил", f"v{preset.version_no}"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return _write_details(
|
return _write_details(
|
||||||
|
|||||||
@ -89,6 +89,18 @@ def test_routes_are_separate_and_matrix_expands_manual_accounts() -> None:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_preset_routes_describe_rule_errors() -> None:
|
||||||
|
preset_routes = [route for route in router.routes if "/intercompany-matrix/preset/{rule_id}" in route.path]
|
||||||
|
assert {route.path for route in preset_routes} == {
|
||||||
|
"/consolidations/versions/{version_id}/intercompany-matrix/preset/{rule_id}",
|
||||||
|
"/consolidations/versions/{version_id}/intercompany-matrix/preset/{rule_id}/export",
|
||||||
|
}
|
||||||
|
for route in preset_routes:
|
||||||
|
assert "правило" in route.responses[404]["description"]
|
||||||
|
description = route.responses[422]["description"]
|
||||||
|
assert all(code in description for code in ("INVALID_RULE", "RULE_REQUIRED", "ACCOUNTS_REQUIRED"))
|
||||||
|
|
||||||
|
|
||||||
async def test_build_pairs_uses_supplied_rows_and_prebuilt_osv(monkeypatch: pytest.MonkeyPatch) -> None:
|
async def test_build_pairs_uses_supplied_rows_and_prebuilt_osv(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
version_id, rule_id, company_a, company_b = (uuid.uuid4() for _ in range(4))
|
version_id, rule_id, company_a, company_b = (uuid.uuid4() for _ in range(4))
|
||||||
full_rows = [object()]
|
full_rows = [object()]
|
||||||
@ -169,14 +181,15 @@ async def test_preset_applies_exclusions_to_its_own_side_and_rule_measure(monkey
|
|||||||
assert info.mode == "PRESET"
|
assert info.mode == "PRESET"
|
||||||
assert info.debit_account_codes == ("76",)
|
assert info.debit_account_codes == ("76",)
|
||||||
assert info.credit_account_codes == ("76",)
|
assert info.credit_account_codes == ("76",)
|
||||||
assert info.debit_excluded_codes == ("76.01",)
|
assert info.preset is not None
|
||||||
assert info.credit_excluded_codes == ()
|
assert info.preset.debit_excluded_codes == ("76.01",)
|
||||||
assert info.rule_side_1 == "D"
|
assert info.preset.credit_excluded_codes == ()
|
||||||
|
assert info.preset.side_1 == "D"
|
||||||
assert info.measure == "turnover"
|
assert info.measure == "turnover"
|
||||||
assert info.rule_no == rule.rule_no
|
assert info.preset.rule_no == rule.rule_no
|
||||||
assert info.rule_version_no == rule.version_no
|
assert info.preset.version_no == rule.version_no
|
||||||
assert info.article_1_line == rule.article_1_line
|
assert info.preset.article_1_line == rule.article_1_line
|
||||||
assert info.article_2_line == rule.article_2_line
|
assert info.preset.article_2_line == rule.article_2_line
|
||||||
|
|
||||||
|
|
||||||
async def test_preset_credit_first_uses_second_side_for_debit(monkeypatch: pytest.MonkeyPatch) -> None:
|
async def test_preset_credit_first_uses_second_side_for_debit(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
|||||||
@ -27,7 +27,7 @@ from src.schemas.consolidations import (
|
|||||||
IntercompanyResultArticleOut,
|
IntercompanyResultArticleOut,
|
||||||
IntercompanyResultTableOut,
|
IntercompanyResultTableOut,
|
||||||
)
|
)
|
||||||
from src.services.intercompany_matrix import MatrixExportInfo, ResultTableExportInfo
|
from src.services.intercompany_matrix import MatrixExportInfo, PresetRuleDetails, ResultTableExportInfo
|
||||||
from src.services.intercompany_matrix_export import (
|
from src.services.intercompany_matrix_export import (
|
||||||
DIAGONAL_FILL,
|
DIAGONAL_FILL,
|
||||||
METRICS,
|
METRICS,
|
||||||
@ -47,38 +47,58 @@ def _info(*, mode: str = "MANUAL", rule_id: UUID | None = None) -> MatrixExportI
|
|||||||
debit_account_codes=("62.01",) if mode != "ALL" else (),
|
debit_account_codes=("62.01",) if mode != "ALL" else (),
|
||||||
credit_account_codes=("60.01",) if mode != "ALL" else (),
|
credit_account_codes=("60.01",) if mode != "ALL" else (),
|
||||||
measure="turnover" if mode == "PRESET" else "closing",
|
measure="turnover" if mode == "PRESET" else "closing",
|
||||||
rule_id=rule_id,
|
preset=PresetRuleDetails(
|
||||||
rule_no=6 if mode == "PRESET" else None,
|
id=rule_id or UUID(int=0),
|
||||||
rule_version_no=3 if mode == "PRESET" else None,
|
rule_no=6,
|
||||||
rule_statement_type=StatementType.balance if mode == "PRESET" else None,
|
version_no=3,
|
||||||
article_1_line="1230" if mode == "PRESET" else None,
|
statement_type=StatementType.balance,
|
||||||
article_2_line="1520" if mode == "PRESET" else None,
|
article_1_line="1230",
|
||||||
rule_side_1="D" if mode == "PRESET" else None,
|
article_2_line="1520",
|
||||||
|
side_1="D",
|
||||||
|
)
|
||||||
|
if mode == "PRESET"
|
||||||
|
else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_preset_header_shows_rule_codes_exclusions_and_credit_first_articles() -> None:
|
def test_preset_header_shows_rule_6_codes_and_exclusions() -> None:
|
||||||
matrix = IntercompanyMatrixOut(companies=[], cells=[])
|
matrix = IntercompanyMatrixOut(companies=[], cells=[])
|
||||||
info = replace(
|
info = replace(
|
||||||
_info(mode="PRESET"),
|
_info(mode="PRESET"),
|
||||||
debit_account_codes=("60.02", "76"),
|
debit_account_codes=("60.02", "60.22", "60.32", "62.01", "62.03", "62.21", "62.31", "76"),
|
||||||
credit_account_codes=("60.01", "76"),
|
credit_account_codes=("60.01", "60.03", "60.21", "60.31", "62.02", "62.22", "62.32", "76"),
|
||||||
debit_excluded_codes=("76.07.5", "76.07.9"),
|
preset=replace(
|
||||||
credit_excluded_codes=("76.07.1",),
|
_info(mode="PRESET").preset,
|
||||||
rule_side_1="K",
|
debit_excluded_codes=("76.07.5", "76.07.9"),
|
||||||
|
credit_excluded_codes=("76.07.1",),
|
||||||
|
side_1="D",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
sheet = load_workbook(BytesIO(build_matrix_workbook(matrix, info))).active
|
sheet = load_workbook(BytesIO(build_matrix_workbook(matrix, info))).active
|
||||||
assert [(sheet.cell(row, 1).value, sheet.cell(row, 2).value) for row in range(7, 16)] == [
|
assert [(sheet.cell(row, 1).value, sheet.cell(row, 2).value) for row in range(7, 16)] == [
|
||||||
("Счета дебета", "60.02, 76"),
|
("Счета дебета", "60.02, 60.22, 60.32, 62.01, 62.03, 62.21, 62.31, 76"),
|
||||||
("кроме", "76.07.5, 76.07.9"),
|
("кроме", "76.07.5, 76.07.9"),
|
||||||
("Счета кредита", "60.01, 76"),
|
("Счета кредита", "60.01, 60.03, 60.21, 60.31, 62.02, 62.22, 62.32, 76"),
|
||||||
("кроме", "76.07.1"),
|
("кроме", "76.07.1"),
|
||||||
("Показатель", "Оборот"),
|
("Показатель", "Оборот"),
|
||||||
("Правило", "ББ № 6"),
|
("Правило", "ББ № 6"),
|
||||||
|
("Статья А", "1230"),
|
||||||
|
("Статья Б", "1520"),
|
||||||
|
("Версия правил", "v3"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_preset_header_swaps_articles_for_credit_first_rule() -> None:
|
||||||
|
matrix = IntercompanyMatrixOut(companies=[], cells=[])
|
||||||
|
info = _info(mode="PRESET")
|
||||||
|
assert info.preset is not None
|
||||||
|
info = replace(info, preset=replace(info.preset, side_1="K"))
|
||||||
|
|
||||||
|
sheet = load_workbook(BytesIO(build_matrix_workbook(matrix, info))).active
|
||||||
|
assert [(sheet.cell(row, 1).value, sheet.cell(row, 2).value) for row in (11, 12)] == [
|
||||||
("Статья А", "1520"),
|
("Статья А", "1520"),
|
||||||
("Статья Б", "1230"),
|
("Статья Б", "1230"),
|
||||||
("Версия правил", "v3"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -284,6 +284,14 @@ SHALL считать исходные строки ОСВ пары с `account_i
|
|||||||
правила, статьи А и Б по дебетовой и кредитовой сторонам соответственно (`article_1_line` / `article_2_line` при `side_1 = D`, наоборот при `side_1 = K`), фактическую версию правил и строку «Показатель» со значением «Сальдо» для `closing` или «Оборот» для `turnover`. Строка «Показатель» SHALL присутствовать и в выгрузках ALL и MANUAL (значение
|
правила, статьи А и Б по дебетовой и кредитовой сторонам соответственно (`article_1_line` / `article_2_line` при `side_1 = D`, наоборот при `side_1 = K`), фактическую версию правил и строку «Показатель» со значением «Сальдо» для `closing` или «Оборот» для `turnover`. Строка «Показатель» SHALL присутствовать и в выгрузках ALL и MANUAL (значение
|
||||||
«Сальдо»).
|
«Сальдо»).
|
||||||
|
|
||||||
|
#### Scenario: Правило № 6 с исключениями
|
||||||
|
- **WHEN** пользователь выгружает пресет правила № 6 из seed-набора Прил. 3
|
||||||
|
- **THEN** шапка показывает исходные коды счетов сторон правила, в отдельной строке дебета «кроме 76.07.5, 76.07.9», а в отдельной строке кредита — «кроме 76.07.1»; раскрытые субсчета счёта 76 в шапку не добавляются
|
||||||
|
|
||||||
|
#### Scenario: Кредитная первая сторона правила
|
||||||
|
- **WHEN** пользователь выгружает пресет с `side_1 = K`
|
||||||
|
- **THEN** «Статья А» содержит `article_2_line`, «Статья Б» — `article_1_line`
|
||||||
|
|
||||||
#### Scenario: Выгрузка по оборотам
|
#### Scenario: Выгрузка по оборотам
|
||||||
- **WHEN** пользователь выгружает пресет с `measure = turnover`
|
- **WHEN** пользователь выгружает пресет с `measure = turnover`
|
||||||
- **THEN** шапка содержит «Режим — Пресет», «Показатель — Оборот», номер, статьи и версию правила; имя файла заканчивается на `_rule-balance-<rule_no>.xlsx`
|
- **THEN** шапка содержит «Режим — Пресет», «Показатель — Оборот», номер, статьи и версию правила; имя файла заканчивается на `_rule-balance-<rule_no>.xlsx`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user