AURORA-1903: лист «Смета» — своя раскладка колонок для каждой формы #287
@ -3386,7 +3386,12 @@ FORM4_OPER_COLORS: dict = _rename_color_paths(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
SMETA_COLUMNS: list[tuple[str, str]] = [
|
# AURORA-1903: у каждой формы на листе "Смета" свой набор колонок, в порядке
|
||||||
|
# её экрана (RealtimeTable constants/FORM_*/SMETA.js). FORM_1 показывает и
|
||||||
|
# поддержку, и развитие, и три группы ИТОГО (план/утверждено/факт); FORM_2
|
||||||
|
# ("Смета РФ") — только поддержку; FORM_4 ("Проектная деятельность") — только
|
||||||
|
# развитие. Ключи совпадают с SMETA_VALUE_PATHS в export_normalizers.py.
|
||||||
|
SMETA_FORM1_COLUMNS: list[tuple[str, str]] = [
|
||||||
("section_code", "Код раздела"),
|
("section_code", "Код раздела"),
|
||||||
("name", "Наименование"),
|
("name", "Наименование"),
|
||||||
("plan_support_q1", "План поддержка I квартал"),
|
("plan_support_q1", "План поддержка I квартал"),
|
||||||
@ -3429,6 +3434,59 @@ SMETA_COLUMNS: list[tuple[str, str]] = [
|
|||||||
("corrected_development_q3", "Корректировка развитие III квартал"),
|
("corrected_development_q3", "Корректировка развитие III квартал"),
|
||||||
("corrected_development_q4", "Корректировка развитие IV квартал"),
|
("corrected_development_q4", "Корректировка развитие IV квартал"),
|
||||||
]
|
]
|
||||||
|
SMETA_FORM2_COLUMNS: list[tuple[str, str]] = [
|
||||||
|
("section_code", "Код раздела"),
|
||||||
|
("name", "Наименование"),
|
||||||
|
("plan_support_q1", "План поддержка I квартал"),
|
||||||
|
("plan_support_q2", "План поддержка II квартал"),
|
||||||
|
("plan_support_q3", "План поддержка III квартал"),
|
||||||
|
("plan_support_q4", "План поддержка IV квартал"),
|
||||||
|
("plan_support_year", "План поддержка Год"),
|
||||||
|
("approved_support_q1", "Утверждено поддержка I квартал"),
|
||||||
|
("approved_support_q2", "Утверждено поддержка II квартал"),
|
||||||
|
("approved_support_q3", "Утверждено поддержка III квартал"),
|
||||||
|
("approved_support_q4", "Утверждено поддержка IV квартал"),
|
||||||
|
("approved_support_year", "Утверждено поддержка Год"),
|
||||||
|
("fact_support_q1", "Факт поддержка I квартал"),
|
||||||
|
("fact_support_q2", "Факт поддержка II квартал"),
|
||||||
|
("fact_support_q3", "Факт поддержка III квартал"),
|
||||||
|
("fact_support_q4", "Факт поддержка IV квартал"),
|
||||||
|
("fact_support_year", "Факт поддержка Год"),
|
||||||
|
("corrected_support_q2", "Корректировка поддержка II квартал"),
|
||||||
|
("corrected_support_q3", "Корректировка поддержка III квартал"),
|
||||||
|
("corrected_support_q4", "Корректировка поддержка IV квартал"),
|
||||||
|
]
|
||||||
|
SMETA_FORM4_COLUMNS: list[tuple[str, str]] = [
|
||||||
|
("section_code", "Код раздела"),
|
||||||
|
("name", "Наименование"),
|
||||||
|
("plan_development_q1", "План развитие I квартал"),
|
||||||
|
("plan_development_q2", "План развитие II квартал"),
|
||||||
|
("plan_development_q3", "План развитие III квартал"),
|
||||||
|
("plan_development_q4", "План развитие IV квартал"),
|
||||||
|
("plan_development_year", "План развитие Год"),
|
||||||
|
("approved_development_q1", "Утверждено развитие I квартал"),
|
||||||
|
("approved_development_q2", "Утверждено развитие II квартал"),
|
||||||
|
("approved_development_q3", "Утверждено развитие III квартал"),
|
||||||
|
("approved_development_q4", "Утверждено развитие IV квартал"),
|
||||||
|
("approved_development_year", "Утверждено развитие Год"),
|
||||||
|
("fact_development_q1", "Факт развитие I квартал"),
|
||||||
|
("fact_development_q2", "Факт развитие II квартал"),
|
||||||
|
("fact_development_q3", "Факт развитие III квартал"),
|
||||||
|
("fact_development_q4", "Факт развитие IV квартал"),
|
||||||
|
("fact_development_year", "Факт развитие Год"),
|
||||||
|
("corrected_development_q2", "Корректировка развитие II квартал"),
|
||||||
|
("corrected_development_q3", "Корректировка развитие III квартал"),
|
||||||
|
("corrected_development_q4", "Корректировка развитие IV квартал"),
|
||||||
|
]
|
||||||
|
SMETA_COLUMNS_BY_FORM: dict[str, list[tuple[str, str]]] = {
|
||||||
|
"FORM_1": SMETA_FORM1_COLUMNS,
|
||||||
|
"FORM_2": SMETA_FORM2_COLUMNS,
|
||||||
|
"FORM_4": SMETA_FORM4_COLUMNS,
|
||||||
|
}
|
||||||
|
# Алиас для обратной совместимости: часть кода (неиспользуемый openpyxl-словарь
|
||||||
|
# writer'ов в ExportService.__init__, старый тест test_sheet_column_contracts_are_stable)
|
||||||
|
# по-прежнему ссылается на единый SMETA_COLUMNS — это раскладка FORM_1.
|
||||||
|
SMETA_COLUMNS: list[tuple[str, str]] = SMETA_COLUMNS_BY_FORM["FORM_1"]
|
||||||
FORM3_LIMIT_DEPTH_COLUMNS: dict = {
|
FORM3_LIMIT_DEPTH_COLUMNS: dict = {
|
||||||
"header": {
|
"header": {
|
||||||
"name": "Данные",
|
"name": "Данные",
|
||||||
|
|||||||
@ -45,6 +45,7 @@ from src.services.export_service.export_mappings import (
|
|||||||
FORM3_LIMIT_DEPTH_COLUMNS,
|
FORM3_LIMIT_DEPTH_COLUMNS,
|
||||||
PALETTE,
|
PALETTE,
|
||||||
SMETA_COLUMNS,
|
SMETA_COLUMNS,
|
||||||
|
SMETA_COLUMNS_BY_FORM,
|
||||||
build_summary1_columns,
|
build_summary1_columns,
|
||||||
build_summary2_columns,
|
build_summary2_columns,
|
||||||
render_column_years,
|
render_column_years,
|
||||||
@ -913,7 +914,7 @@ class ExportService:
|
|||||||
"__default__": default_writer,
|
"__default__": default_writer,
|
||||||
"SMETA": XlsxTabularSheetWriter(
|
"SMETA": XlsxTabularSheetWriter(
|
||||||
workbook=workbook,
|
workbook=workbook,
|
||||||
columns=SMETA_COLUMNS,
|
columns=SMETA_COLUMNS_BY_FORM.get(form_type_code, SMETA_COLUMNS_BY_FORM["FORM_1"]),
|
||||||
row_normalizer=self.smeta_row_normalizer.normalize,
|
row_normalizer=self.smeta_row_normalizer.normalize,
|
||||||
value_serializer=self.value_serializer.to_excel_value,
|
value_serializer=self.value_serializer.to_excel_value,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -78,6 +78,10 @@ class TabularSheetWriter(AbstractWriter):
|
|||||||
worksheet.append(headers)
|
worksheet.append(headers)
|
||||||
self._track_row_widths(column_widths, headers)
|
self._track_row_widths(column_widths, headers)
|
||||||
for row in rows:
|
for row in rows:
|
||||||
|
if row and row[0] == "META":
|
||||||
|
# v_form_view всегда отдаёт служебную строку META первой;
|
||||||
|
# на листе "Смета" ей не место (AURORA-1903).
|
||||||
|
continue
|
||||||
raw_data = row[3] if len(row) > 3 and isinstance(row[3], dict) else {}
|
raw_data = row[3] if len(row) > 3 and isinstance(row[3], dict) else {}
|
||||||
normalized = self.row_normalizer(raw_data)
|
normalized = self.row_normalizer(raw_data)
|
||||||
values = [self.value_serializer(normalized.get(key)) for key, _ in self.columns]
|
values = [self.value_serializer(normalized.get(key)) for key, _ in self.columns]
|
||||||
@ -303,6 +307,10 @@ class XlsxTabularSheetWriter(AbstractWriter):
|
|||||||
|
|
||||||
output_row = 1
|
output_row = 1
|
||||||
for row in rows:
|
for row in rows:
|
||||||
|
if row and row[0] == "META":
|
||||||
|
# v_form_view всегда отдаёт служебную строку META первой;
|
||||||
|
# на листе "Смета" ей не место (AURORA-1903).
|
||||||
|
continue
|
||||||
raw_data = row[3] if len(row) > 3 and isinstance(row[3], dict) else {}
|
raw_data = row[3] if len(row) > 3 and isinstance(row[3], dict) else {}
|
||||||
normalized = self.row_normalizer(raw_data)
|
normalized = self.row_normalizer(raw_data)
|
||||||
values = [self.value_serializer(normalized.get(key)) for key, _ in self.columns]
|
values = [self.value_serializer(normalized.get(key)) for key, _ in self.columns]
|
||||||
|
|||||||
@ -9,13 +9,47 @@ from src.services.export_service import ExportService
|
|||||||
from src.services.export_service.export_mappings import (
|
from src.services.export_service.export_mappings import (
|
||||||
FORM1_FLAT_COLUMNS,
|
FORM1_FLAT_COLUMNS,
|
||||||
SMETA_COLUMNS,
|
SMETA_COLUMNS,
|
||||||
|
SMETA_COLUMNS_BY_FORM,
|
||||||
)
|
)
|
||||||
from src.services.export_service.export_writers import (
|
from src.services.export_service.export_writers import (
|
||||||
DepthSheetWriter,
|
DepthSheetWriter,
|
||||||
TabularSheetWriter,
|
TabularSheetWriter,
|
||||||
XlsxDepthSheetWriter,
|
XlsxDepthSheetWriter,
|
||||||
|
XlsxTabularSheetWriter,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Эталонные порядки колонок листа "Смета" экрана каждой формы (AURORA-1903).
|
||||||
|
SMETA_SCREEN_COLUMNS_BY_FORM = {
|
||||||
|
"FORM_1": [
|
||||||
|
"section_code", "name",
|
||||||
|
"plan_support_q1", "plan_support_q2", "plan_support_q3", "plan_support_q4", "plan_support_year",
|
||||||
|
"plan_development_q1", "plan_development_q2", "plan_development_q3", "plan_development_q4", "plan_development_year",
|
||||||
|
"plan_total_year",
|
||||||
|
"approved_support_q1", "approved_support_q2", "approved_support_q3", "approved_support_q4", "approved_support_year",
|
||||||
|
"approved_development_q1", "approved_development_q2", "approved_development_q3", "approved_development_q4", "approved_development_year",
|
||||||
|
"approved_total_year",
|
||||||
|
"fact_support_q1", "fact_support_q2", "fact_support_q3", "fact_support_q4", "fact_support_year",
|
||||||
|
"fact_development_q1", "fact_development_q2", "fact_development_q3", "fact_development_q4", "fact_development_year",
|
||||||
|
"fact_total_year",
|
||||||
|
"corrected_support_q2", "corrected_support_q3", "corrected_support_q4",
|
||||||
|
"corrected_development_q2", "corrected_development_q3", "corrected_development_q4",
|
||||||
|
],
|
||||||
|
"FORM_2": [
|
||||||
|
"section_code", "name",
|
||||||
|
"plan_support_q1", "plan_support_q2", "plan_support_q3", "plan_support_q4", "plan_support_year",
|
||||||
|
"approved_support_q1", "approved_support_q2", "approved_support_q3", "approved_support_q4", "approved_support_year",
|
||||||
|
"fact_support_q1", "fact_support_q2", "fact_support_q3", "fact_support_q4", "fact_support_year",
|
||||||
|
"corrected_support_q2", "corrected_support_q3", "corrected_support_q4",
|
||||||
|
],
|
||||||
|
"FORM_4": [
|
||||||
|
"section_code", "name",
|
||||||
|
"plan_development_q1", "plan_development_q2", "plan_development_q3", "plan_development_q4", "plan_development_year",
|
||||||
|
"approved_development_q1", "approved_development_q2", "approved_development_q3", "approved_development_q4", "approved_development_year",
|
||||||
|
"fact_development_q1", "fact_development_q2", "fact_development_q3", "fact_development_q4", "fact_development_year",
|
||||||
|
"corrected_development_q2", "corrected_development_q3", "corrected_development_q4",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("backend", ["openpyxl", "xlsxwriter", "xlsxwriter_columns", "xlsxwriter_rows", "xlsxwriter_palette"])
|
@pytest.mark.parametrize("backend", ["openpyxl", "xlsxwriter", "xlsxwriter_columns", "xlsxwriter_rows", "xlsxwriter_palette"])
|
||||||
@pytest.mark.parametrize("name_key", ["name", "header.name"])
|
@pytest.mark.parametrize("name_key", ["name", "header.name"])
|
||||||
@ -87,6 +121,91 @@ def test_sheet_column_contracts_are_stable():
|
|||||||
assert len(SMETA_COLUMNS) == 41
|
assert len(SMETA_COLUMNS) == 41
|
||||||
assert FORM1_FLAT_COLUMNS[0] == ("section", "Код раздела")
|
assert FORM1_FLAT_COLUMNS[0] == ("section", "Код раздела")
|
||||||
assert SMETA_COLUMNS[0] == ("section_code", "Код раздела")
|
assert SMETA_COLUMNS[0] == ("section_code", "Код раздела")
|
||||||
|
# AURORA-1903: SMETA_COLUMNS остаётся алиасом на FORM_1-раскладку.
|
||||||
|
assert SMETA_COLUMNS is SMETA_COLUMNS_BY_FORM["FORM_1"]
|
||||||
|
assert [key for key, _ in SMETA_COLUMNS_BY_FORM["FORM_2"]] == SMETA_SCREEN_COLUMNS_BY_FORM["FORM_2"]
|
||||||
|
assert [key for key, _ in SMETA_COLUMNS_BY_FORM["FORM_4"]] == SMETA_SCREEN_COLUMNS_BY_FORM["FORM_4"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("form_type_code", ["FORM_1", "FORM_2", "FORM_4"])
|
||||||
|
def test_smeta_writer_columns_match_screen_order_per_form(form_type_code):
|
||||||
|
"""AURORA-1903: лист "Смета" каждой формы выгружается в порядке своего экрана."""
|
||||||
|
service = ExportService(AsyncMock())
|
||||||
|
workbook = XlsxWorkbook(BytesIO())
|
||||||
|
writers = service._create_xlsxwriter_sheet_writers(
|
||||||
|
workbook=workbook,
|
||||||
|
form_type_code=form_type_code,
|
||||||
|
year=2024,
|
||||||
|
)
|
||||||
|
smeta_writer = writers["SMETA"]
|
||||||
|
assert [key for key, _ in smeta_writer.columns] == SMETA_SCREEN_COLUMNS_BY_FORM[form_type_code]
|
||||||
|
workbook.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_smeta_writer_falls_back_to_form1_layout_for_unknown_form_type():
|
||||||
|
service = ExportService(AsyncMock())
|
||||||
|
workbook = XlsxWorkbook(BytesIO())
|
||||||
|
writers = service._create_xlsxwriter_sheet_writers(
|
||||||
|
workbook=workbook,
|
||||||
|
form_type_code=None,
|
||||||
|
year=2024,
|
||||||
|
)
|
||||||
|
assert [key for key, _ in writers["SMETA"].columns] == SMETA_SCREEN_COLUMNS_BY_FORM["FORM_1"]
|
||||||
|
workbook.close()
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeXlsxWorksheet:
|
||||||
|
"""Фейковый worksheet, фиксирующий ровно то, что было записано."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.written_rows: dict[int, list] = {}
|
||||||
|
|
||||||
|
def write_row(self, row, col, values):
|
||||||
|
self.written_rows[row] = list(values)
|
||||||
|
|
||||||
|
def set_column(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_xlsx_tabular_sheet_writer_skips_meta_row():
|
||||||
|
writer = XlsxTabularSheetWriter(
|
||||||
|
workbook=object(),
|
||||||
|
columns=[("section_code", "Код раздела"), ("name", "Наименование"), ("plan_support_q1", "План поддержка I квартал")],
|
||||||
|
row_normalizer=lambda row: row,
|
||||||
|
value_serializer=lambda value: value,
|
||||||
|
)
|
||||||
|
worksheet = _FakeXlsxWorksheet()
|
||||||
|
rows = [
|
||||||
|
("META", -1, 0, {"ignored": True}),
|
||||||
|
("ROOT", 0, 1, {"section_code": "1", "name": "x", "plan_support_q1": 10}),
|
||||||
|
]
|
||||||
|
writer.write(worksheet, rows)
|
||||||
|
|
||||||
|
assert set(worksheet.written_rows.keys()) == {0, 1}
|
||||||
|
assert worksheet.written_rows[0] == ["Код раздела", "Наименование", "План поддержка I квартал"]
|
||||||
|
assert worksheet.written_rows[1] == ["1", "x", 10]
|
||||||
|
|
||||||
|
|
||||||
|
def test_tabular_sheet_writer_skips_meta_row_openpyxl():
|
||||||
|
writer = TabularSheetWriter(
|
||||||
|
columns=[("a", "A"), ("b", "B")],
|
||||||
|
row_normalizer=lambda row: row,
|
||||||
|
value_serializer=lambda value: value,
|
||||||
|
)
|
||||||
|
wb = Workbook()
|
||||||
|
ws = wb.active
|
||||||
|
|
||||||
|
rows = [
|
||||||
|
("META", -1, 0, {"a": "should-not-appear", "b": "should-not-appear"}),
|
||||||
|
("ROOT", 0, 1, {"a": 1, "b": 2}),
|
||||||
|
]
|
||||||
|
writer.write(ws, rows)
|
||||||
|
|
||||||
|
assert ws.cell(row=1, column=1).value == "A"
|
||||||
|
assert ws.cell(row=1, column=2).value == "B"
|
||||||
|
assert ws.cell(row=2, column=1).value == 1
|
||||||
|
assert ws.cell(row=2, column=2).value == 2
|
||||||
|
assert ws.cell(row=3, column=1).value is None
|
||||||
|
|
||||||
|
|
||||||
def test_export_service_uses_sheet_writer_strategy():
|
def test_export_service_uses_sheet_writer_strategy():
|
||||||
|
|||||||
@ -569,6 +569,37 @@ export const config = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: "Итого: {year}",
|
||||||
|
accessorKey: "itogo_2024_utverzhdennye",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: "",
|
||||||
|
accessorKey: "itogo_2024_utverzhdennye_field",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: "",
|
||||||
|
accessorKey: "itogo_2024_utverzhdennye_field_field",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: "",
|
||||||
|
accessorKey: "data.approved.total_year",
|
||||||
|
columnLetter: "Z",
|
||||||
|
size: 150,
|
||||||
|
filterFn: "contains",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
muiTableHeadCellProps: {
|
||||||
|
sx: {
|
||||||
|
backgroundColor: "#BFBFBF",
|
||||||
|
color: "#000000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: "Фактические расходы за {year} год",
|
header: "Фактические расходы за {year} год",
|
||||||
accessorKey: "fakticheskie_raskhody_za_2024_god",
|
accessorKey: "fakticheskie_raskhody_za_2024_god",
|
||||||
@ -805,6 +836,37 @@ export const config = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: "Итого: {year}",
|
||||||
|
accessorKey: "itogo_2024_fakticheskie",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: "",
|
||||||
|
accessorKey: "itogo_2024_fakticheskie_field",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: "",
|
||||||
|
accessorKey: "itogo_2024_fakticheskie_field_field",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: "",
|
||||||
|
accessorKey: "data.fact.total_year",
|
||||||
|
columnLetter: "AL",
|
||||||
|
size: 150,
|
||||||
|
filterFn: "contains",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
muiTableHeadCellProps: {
|
||||||
|
sx: {
|
||||||
|
backgroundColor: "#BFBFBF",
|
||||||
|
color: "#000000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: "Скорректированная смета расходов на {year} год",
|
header: "Скорректированная смета расходов на {year} год",
|
||||||
accessorKey: "skorrektirovannaya_smeta_raskhodov_na_2024_god",
|
accessorKey: "skorrektirovannaya_smeta_raskhodov_na_2024_god",
|
||||||
|
|||||||
@ -0,0 +1,84 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import test from 'node:test';
|
||||||
|
|
||||||
|
// SMETA.js is imported elsewhere via an extensionless path ("../columnColors")
|
||||||
|
// that only the project's bundler (Rsbuild) resolves, so plain `node --test`
|
||||||
|
// cannot `import` this module directly (ERR_MODULE_NOT_FOUND). Per AURORA-1903
|
||||||
|
// and its precedent (AURORA-1901's form2SmetaConfig test), we instead match the
|
||||||
|
// file's text for its `accessorKey: "data...."` leaves and assert their order.
|
||||||
|
const sourcePath = fileURLToPath(new URL('./SMETA.js', import.meta.url));
|
||||||
|
const source = readFileSync(sourcePath, 'utf8');
|
||||||
|
|
||||||
|
// AURORA-1903: экран формы 1 должен показывать "Утверждено ИТОГО Год" (Z) и
|
||||||
|
// "Факт ИТОГО Год" (AL) — раньше их теряли, хотя SQL (v_form_view) всегда их
|
||||||
|
// отдавал и выгрузка Excel их писала. Порядок ниже — источник истины для
|
||||||
|
// колонок листа "Смета" формы 1: он литерально совпадает с порядком ключей
|
||||||
|
// SMETA_COLUMNS_BY_FORM["FORM_1"] в api/src/services/export_service/export_mappings.py.
|
||||||
|
const EXPECTED_DATA_ACCESSOR_KEY_ORDER = [
|
||||||
|
'data.section_code',
|
||||||
|
'data.name',
|
||||||
|
'data.plan.support.q1',
|
||||||
|
'data.plan.support.q2',
|
||||||
|
'data.plan.support.q3',
|
||||||
|
'data.plan.support.q4',
|
||||||
|
'data.plan.support.year',
|
||||||
|
'data.plan.development.q1',
|
||||||
|
'data.plan.development.q2',
|
||||||
|
'data.plan.development.q3',
|
||||||
|
'data.plan.development.q4',
|
||||||
|
'data.plan.development.year',
|
||||||
|
'data.plan.total_year',
|
||||||
|
'data.approved.support.q1',
|
||||||
|
'data.approved.support.q2',
|
||||||
|
'data.approved.support.q3',
|
||||||
|
'data.approved.support.q4',
|
||||||
|
'data.approved.support.year',
|
||||||
|
'data.approved.development.q1',
|
||||||
|
'data.approved.development.q2',
|
||||||
|
'data.approved.development.q3',
|
||||||
|
'data.approved.development.q4',
|
||||||
|
'data.approved.development.year',
|
||||||
|
'data.approved.total_year',
|
||||||
|
'data.fact.support.q1',
|
||||||
|
'data.fact.support.q2',
|
||||||
|
'data.fact.support.q3',
|
||||||
|
'data.fact.support.q4',
|
||||||
|
'data.fact.support.year',
|
||||||
|
'data.fact.development.q1',
|
||||||
|
'data.fact.development.q2',
|
||||||
|
'data.fact.development.q3',
|
||||||
|
'data.fact.development.q4',
|
||||||
|
'data.fact.development.year',
|
||||||
|
'data.fact.total_year',
|
||||||
|
'data.corrected.support.q2',
|
||||||
|
'data.corrected.support.q3',
|
||||||
|
'data.corrected.support.q4',
|
||||||
|
'data.corrected.development.q2',
|
||||||
|
'data.corrected.development.q3',
|
||||||
|
'data.corrected.development.q4',
|
||||||
|
];
|
||||||
|
|
||||||
|
function extractDataAccessorKeysInOrder(text) {
|
||||||
|
const re = /accessorKey:\s*"(data\.[^"]+)"/g;
|
||||||
|
const keys = [];
|
||||||
|
let match;
|
||||||
|
while ((match = re.exec(text)) !== null) {
|
||||||
|
keys.push(match[1]);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
test('FORM_1 SMETA screen leaf accessorKeys are in the ticket-mandated order (AURORA-1903)', () => {
|
||||||
|
const keys = extractDataAccessorKeysInOrder(source);
|
||||||
|
assert.deepEqual(keys, EXPECTED_DATA_ACCESSOR_KEY_ORDER);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('FORM_1 SMETA screen has exactly one approved.total_year (Z) and one fact.total_year (AL) column', () => {
|
||||||
|
const keys = extractDataAccessorKeysInOrder(source);
|
||||||
|
assert.equal(keys.filter((key) => key === 'data.approved.total_year').length, 1);
|
||||||
|
assert.equal(keys.filter((key) => key === 'data.fact.total_year').length, 1);
|
||||||
|
assert.match(source, /accessorKey:\s*"data\.approved\.total_year"[\s\S]{0,80}columnLetter:\s*"Z"/);
|
||||||
|
assert.match(source, /accessorKey:\s*"data\.fact\.total_year"[\s\S]{0,80}columnLetter:\s*"AL"/);
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user