Merge dev into main for customer release #17

Merged
avm merged 14 commits from feature/customer-release-20260811 into main 2026-08-11 13:35:31 +03:00
2 changed files with 67 additions and 2 deletions
Showing only changes of commit 1662f49810 - Show all commits

View File

@@ -1168,6 +1168,7 @@ class ExchangePackageImportService:
skipped_count = 0
created_lines_count = 0
updated_lines_count = 0
deleted_lines_count = 0
for row in rows:
organization = cls._resolve_organization(
@@ -1218,6 +1219,7 @@ class ExchangePackageImportService:
)
created_lines_count += line_result["created"]
updated_lines_count += line_result["updated"]
deleted_lines_count += line_result["deleted"]
return {
"created": created_count,
@@ -1225,6 +1227,7 @@ class ExchangePackageImportService:
"skipped": skipped_count,
"created_lines": created_lines_count,
"updated_lines": updated_lines_count,
"deleted_lines": deleted_lines_count,
}
@classmethod
@@ -1234,7 +1237,7 @@ class ExchangePackageImportService:
lines: Any,
) -> dict[str, int]:
if lines is None:
return {"created": 0, "updated": 0}
return {"created": 0, "updated": 0, "deleted": 0}
if not isinstance(lines, list):
raise ExchangeImportError(
"Поле lines финансового отчета должно быть списком"
@@ -1242,6 +1245,7 @@ class ExchangePackageImportService:
created_count = 0
updated_count = 0
expected_keys: set[tuple[str, str, int]] = set()
for line in lines:
if not isinstance(line, dict):
raise ExchangeImportError(
@@ -1252,6 +1256,7 @@ class ExchangePackageImportService:
if not form_code or not line_code:
continue
year = cls._parse_int_value(line.get("year"), field_name="year")
expected_keys.add((form_code, line_code, year))
defaults = {
"line_name": cls._clean_string(line.get("line_name")),
@@ -1281,7 +1286,22 @@ class ExchangePackageImportService:
elif state == "updated":
updated_count += 1
return {"created": created_count, "updated": updated_count}
stale_line_ids = [
line.pk
for line in report.lines.all()
if (line.form_code, line.line_code, line.year) not in expected_keys
]
deleted_count = 0
if stale_line_ids:
deleted_count = FinancialReportLine.objects.filter(
pk__in=stale_line_ids
).delete()[0]
return {
"created": created_count,
"updated": updated_count,
"deleted": deleted_count,
}
@classmethod
def _upsert_arbitration_cases(

View File

@@ -769,6 +769,51 @@ class ExchangePackageApiTest(APITestCase):
duplicate_import = ExchangePackageImport.objects.order_by("-created_at").first()
self.assertIsNotNone(duplicate_import.duplicate_of)
def test_upload_replaces_stale_financial_report_lines(self):
first_payload = build_exchange_payload()
first_archive = build_exchange_archive(
package_id="pkg-financial-year-2025",
data=first_payload,
)
first_response = self.client.post(
self.url,
{"file": first_archive},
format="multipart",
HTTP_X_EXCHANGE_TOKEN=TEST_TOKEN,
)
self.assertEqual(first_response.status_code, status.HTTP_201_CREATED)
self.assertEqual(
list(FinancialReportLine.objects.values_list("year", flat=True)),
[2025],
)
second_payload = build_exchange_payload()
second_payload["financial_reports"][0]["lines"][0]["year"] = 2026
second_archive = build_exchange_archive(
package_id="pkg-financial-year-2026",
data=second_payload,
)
second_response = self.client.post(
self.url,
{"file": second_archive},
format="multipart",
HTTP_X_EXCHANGE_TOKEN=TEST_TOKEN,
)
self.assertEqual(second_response.status_code, status.HTTP_201_CREATED)
self.assertEqual(
list(FinancialReportLine.objects.values_list("year", flat=True)),
[2026],
)
self.assertEqual(
second_response.data["result"]["financial_reports"]["created_lines"],
1,
)
self.assertEqual(
second_response.data["result"]["financial_reports"]["deleted_lines"],
1,
)
def test_cli_import_uses_same_pipeline(self):
archive = build_exchange_archive(
package_id="pkg-cli-001",