From 2d7b299ba7d04ef53730893470fd3c417dd7007e Mon Sep 17 00:00:00 2001 From: SilviaAmAm Date: Fri, 29 Nov 2024 12:12:03 +0100 Subject: [PATCH 1/6] :heavy_plus_sign: [#502] Add XlsxWriter --- backend/requirements/base.in | 3 ++- backend/requirements/base.txt | 2 ++ backend/requirements/ci.txt | 4 ++++ backend/requirements/dev.txt | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/requirements/base.in b/backend/requirements/base.in index c7d92344..0310fcde 100644 --- a/backend/requirements/base.in +++ b/backend/requirements/base.in @@ -37,4 +37,5 @@ celery # Additional libraries zgw-consumers furl -python-slugify \ No newline at end of file +python-slugify +XlsxWriter \ No newline at end of file diff --git a/backend/requirements/base.txt b/backend/requirements/base.txt index 35792ec0..21fc7b12 100644 --- a/backend/requirements/base.txt +++ b/backend/requirements/base.txt @@ -261,5 +261,7 @@ webauthn==2.1.0 # via django-two-factor-auth wrapt==1.14.1 # via elastic-apm +xlsxwriter==3.2.0 + # via -r requirements/base.in zgw-consumers==0.36.1 # via -r requirements/base.in diff --git a/backend/requirements/ci.txt b/backend/requirements/ci.txt index 57e46ae4..29a8cb4a 100644 --- a/backend/requirements/ci.txt +++ b/backend/requirements/ci.txt @@ -630,6 +630,10 @@ wrapt==1.14.1 # -r requirements/base.txt # elastic-apm # vcrpy +xlsxwriter==3.2.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt yarl==1.9.4 # via vcrpy zgw-consumers==0.36.1 diff --git a/backend/requirements/dev.txt b/backend/requirements/dev.txt index 4057380a..e449962e 100644 --- a/backend/requirements/dev.txt +++ b/backend/requirements/dev.txt @@ -820,6 +820,10 @@ wrapt==1.14.1 # -r requirements/ci.txt # elastic-apm # vcrpy +xlsxwriter==3.2.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt yarl==1.9.4 # via # -c requirements/ci.txt From 1b771a67423c0aabaf74e77c857aedfb3f13e185 Mon Sep 17 00:00:00 2001 From: SilviaAmAm Date: Fri, 29 Nov 2024 13:23:53 +0100 Subject: [PATCH 2/6] :heavy_plus_sign: [#502] Add test dependency openpyxl --- backend/requirements/ci.txt | 4 ++++ backend/requirements/dev.txt | 9 +++++++++ backend/requirements/test-tools.in | 3 +++ 3 files changed, 16 insertions(+) diff --git a/backend/requirements/ci.txt b/backend/requirements/ci.txt index 29a8cb4a..4745e0ea 100644 --- a/backend/requirements/ci.txt +++ b/backend/requirements/ci.txt @@ -280,6 +280,8 @@ elastic-apm==6.22.0 # via # -c requirements/base.txt # -r requirements/base.txt +et-xmlfile==2.0.0 + # via openpyxl face==20.1.1 # via # -c requirements/base.txt @@ -369,6 +371,8 @@ multidict==6.0.5 # via yarl mypy-extensions==1.0.0 # via black +openpyxl==3.1.5 + # via -r requirements/test-tools.in orderedmultidict==1.0.1 # via # -c requirements/base.txt diff --git a/backend/requirements/dev.txt b/backend/requirements/dev.txt index e449962e..ef49ced7 100644 --- a/backend/requirements/dev.txt +++ b/backend/requirements/dev.txt @@ -324,6 +324,11 @@ elastic-apm==6.22.0 # via # -c requirements/ci.txt # -r requirements/ci.txt +et-xmlfile==2.0.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # openpyxl face==20.1.1 # via # -c requirements/ci.txt @@ -456,6 +461,10 @@ mypy-extensions==1.0.0 # -c requirements/ci.txt # -r requirements/ci.txt # black +openpyxl==3.1.5 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt orderedmultidict==1.0.1 # via # -c requirements/ci.txt diff --git a/backend/requirements/test-tools.in b/backend/requirements/test-tools.in index 51970124..5c81c5a1 100644 --- a/backend/requirements/test-tools.in +++ b/backend/requirements/test-tools.in @@ -17,6 +17,9 @@ testfixtures vcrpy pytest-playwright docker +# XlsxWriter is more suitable for writing large files, but doesn't support reading them. +# So for the tests we use openpyxl to check the created excel files. +openpyxl # Documentation sphinx From 678940025d96cba5a6fcacd244f001148f89377d Mon Sep 17 00:00:00 2001 From: SilviaAmAm Date: Fri, 29 Nov 2024 14:58:34 +0100 Subject: [PATCH 3/6] :recycle: [#502] Make excell file instead of CSV --- .../openarchiefbeheer/destruction/models.py | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/backend/src/openarchiefbeheer/destruction/models.py b/backend/src/openarchiefbeheer/destruction/models.py index fee18352..d486233e 100644 --- a/backend/src/openarchiefbeheer/destruction/models.py +++ b/backend/src/openarchiefbeheer/destruction/models.py @@ -1,4 +1,3 @@ -import csv import logging import traceback import uuid as _uuid @@ -11,8 +10,9 @@ from django.db import models from django.db.models import QuerySet from django.utils import timezone -from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext, gettext_lazy as _ +import xlsxwriter from privates.fields import PrivateMediaFileField from slugify import slugify from timeline_logger.models import TimelineLog @@ -235,33 +235,38 @@ def generate_destruction_report(self) -> None: "zaaktype omschrijving", "selectielijst procestype nummer", ] - with NamedTemporaryFile(mode="w", newline="", delete_on_close=False) as f_tmp: - writer = csv.DictWriter(f_tmp, fieldnames=fieldnames) - writer.writeheader() - for item in self.items.filter( - processing_status=InternalStatus.succeeded - ).iterator(chunk_size=1000): - data = { - **item.extra_zaak_data, - **{ - "zaaktype url": item.extra_zaak_data["zaaktype"]["url"], - "zaaktype omschrijving": item.extra_zaak_data["zaaktype"][ - "omschrijving" - ], - "selectielijst procestype nummer": item.extra_zaak_data[ - "zaaktype" - ]["selectielijst_procestype"]["nummer"], - }, - } - del data["zaaktype"] - - writer.writerow(data) + with NamedTemporaryFile(mode="wb", delete_on_close=False) as f_tmp: + workbook = xlsxwriter.Workbook(f_tmp.name, options={"in_memory": False}) + worksheet = workbook.add_worksheet(name=gettext("Deleted zaken")) + worksheet.write_row(0, 0, fieldnames) + + for row_count, item in enumerate( + self.items.filter(processing_status=InternalStatus.succeeded).iterator( + chunk_size=1000 + ) + ): + data = [ + item.extra_zaak_data["url"], + item.extra_zaak_data["einddatum"], + item.extra_zaak_data["resultaat"], + item.extra_zaak_data["startdatum"], + item.extra_zaak_data["omschrijving"], + item.extra_zaak_data["identificatie"], + item.extra_zaak_data["zaaktype"]["url"], + item.extra_zaak_data["zaaktype"]["omschrijving"], + item.extra_zaak_data["zaaktype"]["selectielijst_procestype"][ + "nummer" + ], + ] + + worksheet.write_row(row_count + 1, 0, data) + workbook.close() f_tmp.close() - with open(f_tmp.name, mode="r") as f: + with open(f_tmp.name, mode="rb") as f: django_file = File(f) self.destruction_report.save( - f"report_{slugify(self.name)}.csv", django_file + f"report_{slugify(self.name)}.xlsx", django_file ) self.save() From 5ceef99a6e1a3264ac38ca4281745aaa5bba93a5 Mon Sep 17 00:00:00 2001 From: SilviaAmAm Date: Fri, 29 Nov 2024 14:59:00 +0100 Subject: [PATCH 4/6] :white_check_mark: [#502] Update tests --- .../destruction/tests/test_models.py | 65 ++++++++++++++--- .../destruction/tests/test_tasks.py | 71 +++++++++++++++---- 2 files changed, 112 insertions(+), 24 deletions(-) diff --git a/backend/src/openarchiefbeheer/destruction/tests/test_models.py b/backend/src/openarchiefbeheer/destruction/tests/test_models.py index 555d8773..b743c15b 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/test_models.py +++ b/backend/src/openarchiefbeheer/destruction/tests/test_models.py @@ -4,8 +4,10 @@ from django.core.exceptions import ObjectDoesNotExist from django.test import TestCase from django.utils import timezone +from django.utils.translation import gettext from freezegun import freeze_time +from openpyxl import load_workbook from privates.test import temp_private_root from requests import HTTPError from requests_mock import Mocker @@ -344,25 +346,66 @@ def test_generate_destruction_report(self): destruction_list.refresh_from_db() - destruction_list.destruction_report - lines = [line for line in destruction_list.destruction_report.readlines()] + wb = load_workbook(filename=destruction_list.destruction_report.path) + sheet_deleted_zaken = wb[gettext("Deleted zaken")] + rows = list(sheet_deleted_zaken.iter_rows(values_only=True)) - self.assertEqual(len(lines), 4) + self.assertEqual(len(rows), 4) self.assertEqual( - lines[0], - b"url,einddatum,resultaat,startdatum,omschrijving,identificatie,zaaktype url,zaaktype omschrijving,selectielijst procestype nummer\n", + rows[0], + ( + "url", + "einddatum", + "resultaat", + "startdatum", + "omschrijving", + "identificatie", + "zaaktype url", + "zaaktype omschrijving", + "selectielijst procestype nummer", + ), ) self.assertEqual( - lines[1], - b"http://zaken.nl/api/v1/zaken/111-111-111,2022-01-01,http://zaken.nl/api/v1/resultaten/111-111-111,2020-01-01,Test description 1,ZAAK-01,http://catalogi.nl/api/v1/zaaktypen/111-111-111,Tralala zaaktype,1\n", + rows[1], + ( + "http://zaken.nl/api/v1/zaken/111-111-111", + "2022-01-01", + "http://zaken.nl/api/v1/resultaten/111-111-111", + "2020-01-01", + "Test description 1", + "ZAAK-01", + "http://catalogi.nl/api/v1/zaaktypen/111-111-111", + "Tralala zaaktype", + 1, + ), ) self.assertEqual( - lines[2], - b"http://zaken.nl/api/v1/zaken/111-111-222,2022-01-02,http://zaken.nl/api/v1/resultaten/111-111-222,2020-01-02,Test description 2,ZAAK-02,http://catalogi.nl/api/v1/zaaktypen/111-111-111,Tralala zaaktype,1\n", + rows[2], + ( + "http://zaken.nl/api/v1/zaken/111-111-222", + "2022-01-02", + "http://zaken.nl/api/v1/resultaten/111-111-222", + "2020-01-02", + "Test description 2", + "ZAAK-02", + "http://catalogi.nl/api/v1/zaaktypen/111-111-111", + "Tralala zaaktype", + 1, + ), ) self.assertEqual( - lines[3], - b"http://zaken.nl/api/v1/zaken/111-111-333,2022-01-03,http://zaken.nl/api/v1/resultaten/111-111-333,2020-01-03,Test description 3,ZAAK-03,http://catalogi.nl/api/v1/zaaktypen/111-111-222,Tralala zaaktype,2\n", + rows[3], + ( + "http://zaken.nl/api/v1/zaken/111-111-333", + "2022-01-03", + "http://zaken.nl/api/v1/resultaten/111-111-333", + "2020-01-03", + "Test description 3", + "ZAAK-03", + "http://catalogi.nl/api/v1/zaaktypen/111-111-222", + "Tralala zaaktype", + 2, + ), ) def test_zaak_creation_skipped_if_internal_status_succeeded(self): diff --git a/backend/src/openarchiefbeheer/destruction/tests/test_tasks.py b/backend/src/openarchiefbeheer/destruction/tests/test_tasks.py index ab142e68..47377185 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/test_tasks.py +++ b/backend/src/openarchiefbeheer/destruction/tests/test_tasks.py @@ -7,6 +7,7 @@ from django.utils.translation import gettext as _, ngettext from freezegun import freeze_time +from openpyxl import load_workbook from privates.test import temp_private_root from requests import HTTPError from requests_mock import Mocker @@ -439,16 +440,38 @@ def test_process_list(self): ).exists() ) - lines = [line for line in destruction_list.destruction_report.readlines()] + wb = load_workbook(filename=destruction_list.destruction_report.path) + sheet_deleted_zaken = wb[_("Deleted zaken")] + rows = list(sheet_deleted_zaken.iter_rows(values_only=True)) - self.assertEqual(len(lines), 3) + self.assertEqual(len(rows), 3) self.assertEqual( - lines[1], - b"http://zaken.nl/api/v1/zaken/111-111-111,2022-01-01,http://zaken.nl/api/v1/resultaten/111-111-111,2020-01-01,Test description 1,ZAAK-01,http://catalogue-api.nl/zaaktypen/111-111-111,Aangifte behandelen,1\n", + rows[1], + ( + "http://zaken.nl/api/v1/zaken/111-111-111", + "2022-01-01", + "http://zaken.nl/api/v1/resultaten/111-111-111", + "2020-01-01", + "Test description 1", + "ZAAK-01", + "http://catalogue-api.nl/zaaktypen/111-111-111", + "Aangifte behandelen", + 1, + ), ) self.assertEqual( - lines[2], - b"http://zaken.nl/api/v1/zaken/222-222-222,2022-01-02,http://zaken.nl/api/v1/resultaten/111-111-222,2020-01-02,Test description 2,ZAAK-02,http://catalogue-api.nl/zaaktypen/111-111-111,Aangifte behandelen,1\n", + rows[2], + ( + "http://zaken.nl/api/v1/zaken/222-222-222", + "2022-01-02", + "http://zaken.nl/api/v1/resultaten/111-111-222", + "2020-01-02", + "Test description 2", + "ZAAK-02", + "http://catalogue-api.nl/zaaktypen/111-111-111", + "Aangifte behandelen", + 1, + ), ) m_zaak.assert_called() @@ -583,19 +606,41 @@ def test_complete_and_notify(self): self.assertEqual(destruction_list.processing_status, InternalStatus.succeeded) self.assertEqual( destruction_list.destruction_report.name, - "destruction_reports/2024/10/09/report_some-destruction-list.csv", + "destruction_reports/2024/10/09/report_some-destruction-list.xlsx", ) - lines = [line for line in destruction_list.destruction_report.readlines()] + wb = load_workbook(filename=destruction_list.destruction_report.path) + sheet_deleted_zaken = wb[_("Deleted zaken")] + rows = list(sheet_deleted_zaken.iter_rows(values_only=True)) - self.assertEqual(len(lines), 2) + self.assertEqual(len(rows), 2) self.assertEqual( - lines[0], - b"url,einddatum,resultaat,startdatum,omschrijving,identificatie,zaaktype url,zaaktype omschrijving,selectielijst procestype nummer\n", + rows[0], + ( + "url", + "einddatum", + "resultaat", + "startdatum", + "omschrijving", + "identificatie", + "zaaktype url", + "zaaktype omschrijving", + "selectielijst procestype nummer", + ), ) self.assertEqual( - lines[1], - b"http://zaken.nl/api/v1/zaken/111-111-111,2022-01-01,http://zaken.nl/api/v1/resultaten/111-111-111,2020-01-01,Test description 1,ZAAK-01,http://catalogi.nl/api/v1/zaaktypen/111-111-111,Tralala zaaktype,1\n", + rows[1], + ( + "http://zaken.nl/api/v1/zaken/111-111-111", + "2022-01-01", + "http://zaken.nl/api/v1/resultaten/111-111-111", + "2020-01-01", + "Test description 1", + "ZAAK-01", + "http://catalogi.nl/api/v1/zaaktypen/111-111-111", + "Tralala zaaktype", + 1, + ), ) @override_settings(CELERY_TASK_ALWAYS_EAGER=True) From aa63b974d7c1c69e34b3384c311fa8626dc6495d Mon Sep 17 00:00:00 2001 From: SilviaAmAm Date: Mon, 2 Dec 2024 11:32:49 +0100 Subject: [PATCH 5/6] :construction: [#502] Update Mime type --- ...eDestructionReportTest.test_create_destruction_report.yaml | 4 ++-- backend/src/openarchiefbeheer/destruction/utils.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/openarchiefbeheer/destruction/tests/vcr/cassettes/CreateDestructionReportTest.test_create_destruction_report.yaml b/backend/src/openarchiefbeheer/destruction/tests/vcr/cassettes/CreateDestructionReportTest.test_create_destruction_report.yaml index 38731194..a786e718 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/vcr/cassettes/CreateDestructionReportTest.test_create_destruction_report.yaml +++ b/backend/src/openarchiefbeheer/destruction/tests/vcr/cassettes/CreateDestructionReportTest.test_create_destruction_report.yaml @@ -153,7 +153,7 @@ interactions: - request: body: '{"bronorganisatie": "000000000", "creatiedatum": "2024-10-14", "titel": "Destruction report of list: trouble", "auteur": "Open Archiefbeheer", "taal": - "nld", "formaat": "text/csv", "inhoud": "c29tZSBkYXRh", "informatieobjecttype": + "nld", "formaat": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "inhoud": "c29tZSBkYXRh", "informatieobjecttype": "http://localhost:8003/catalogi/api/v1/informatieobjecttypen/9dee6712-122e-464a-99a3-c16692de5485", "indicatie_gebruiksrecht": false}' headers: @@ -177,7 +177,7 @@ interactions: body: string: '{"url":"http://localhost:8003/documenten/api/v1/enkelvoudiginformatieobjecten/174fc1c3-36fe-4ed1-b2c4-b0368efa2008","identificatie":"DOCUMENT-2024-0000000003","bronorganisatie":"000000000","creatiedatum":"2024-10-14","titel":"Destruction report of list: trouble","vertrouwelijkheidaanduiding":"openbaar","auteur":"Open - Archiefbeheer","status":"","formaat":"text/csv","taal":"nld","versie":1,"beginRegistratie":"2024-10-14T13:13:05.150793Z","bestandsnaam":"","inhoud":"http://localhost:8003/documenten/api/v1/enkelvoudiginformatieobjecten/174fc1c3-36fe-4ed1-b2c4-b0368efa2008/download?versie=1","bestandsomvang":9,"link":"","beschrijving":"","ontvangstdatum":null,"verzenddatum":null,"indicatieGebruiksrecht":false,"verschijningsvorm":"","ondertekening":{"soort":"","datum":null},"integriteit":{"algoritme":"","waarde":"","datum":null},"informatieobjecttype":"http://localhost:8003/catalogi/api/v1/informatieobjecttypen/9dee6712-122e-464a-99a3-c16692de5485","locked":false,"bestandsdelen":[],"trefwoorden":[],"lock":""}' + Archiefbeheer","status":"","formaat":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","taal":"nld","versie":1,"beginRegistratie":"2024-10-14T13:13:05.150793Z","bestandsnaam":"","inhoud":"http://localhost:8003/documenten/api/v1/enkelvoudiginformatieobjecten/174fc1c3-36fe-4ed1-b2c4-b0368efa2008/download?versie=1","bestandsomvang":9,"link":"","beschrijving":"","ontvangstdatum":null,"verzenddatum":null,"indicatieGebruiksrecht":false,"verschijningsvorm":"","ondertekening":{"soort":"","datum":null},"integriteit":{"algoritme":"","waarde":"","datum":null},"informatieobjecttype":"http://localhost:8003/catalogi/api/v1/informatieobjecttypen/9dee6712-122e-464a-99a3-c16692de5485","locked":false,"bestandsdelen":[],"trefwoorden":[],"lock":""}' headers: API-version: - 1.4.2 diff --git a/backend/src/openarchiefbeheer/destruction/utils.py b/backend/src/openarchiefbeheer/destruction/utils.py index cb9101a0..c97f74e1 100644 --- a/backend/src/openarchiefbeheer/destruction/utils.py +++ b/backend/src/openarchiefbeheer/destruction/utils.py @@ -224,7 +224,7 @@ def create_eio_destruction_report( % {"list_name": destruction_list.name}, "auteur": "Open Archiefbeheer", "taal": "nld", - "formaat": "text/csv", + "formaat": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "inhoud": b64encode(f_report.read()).decode("utf-8"), "informatieobjecttype": config.informatieobjecttype, "indicatie_gebruiksrecht": False, From 4c2b867e9cafb32c0f2aacbc0b2a54d9077047c8 Mon Sep 17 00:00:00 2001 From: SilviaAmAm Date: Tue, 3 Dec 2024 15:37:37 +0100 Subject: [PATCH 6/6] :recycle: [#502] Recycle generation destruction report Make the mapping between field names and value more maintainable --- .../destruction/destruction_report.py | 43 ++++++++++++++++++ .../openarchiefbeheer/destruction/models.py | 45 +++---------------- .../openarchiefbeheer/zaken/api/constants.py | 15 +++++++ .../zaken/api/serializers.py | 2 + 4 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 backend/src/openarchiefbeheer/destruction/destruction_report.py create mode 100644 backend/src/openarchiefbeheer/zaken/api/constants.py diff --git a/backend/src/openarchiefbeheer/destruction/destruction_report.py b/backend/src/openarchiefbeheer/destruction/destruction_report.py new file mode 100644 index 00000000..596adfa7 --- /dev/null +++ b/backend/src/openarchiefbeheer/destruction/destruction_report.py @@ -0,0 +1,43 @@ +from dataclasses import dataclass +from typing import IO + +from django.utils.translation import gettext + +import xlsxwriter +from glom import glom +from xlsxwriter.worksheet import Worksheet + +from openarchiefbeheer.zaken.api.constants import ZAAK_METADATA_FIELDS_MAPPINGS + +from .constants import InternalStatus +from .models import DestructionList + + +@dataclass +class DestructionReportGenerator: + destruction_list: DestructionList + + def add_zaken_table(self, worksheet: Worksheet, start_row: int = 0) -> None: + worksheet.write_row( + start_row, 0, [field["name"] for field in ZAAK_METADATA_FIELDS_MAPPINGS] + ) + + for row_count, item in enumerate( + self.destruction_list.items.filter( + processing_status=InternalStatus.succeeded + ).iterator(chunk_size=1000) + ): + data = [ + glom(item.extra_zaak_data, field["path"], default="") + for field in ZAAK_METADATA_FIELDS_MAPPINGS + ] + worksheet.write_row(start_row + row_count + 1, 0, data) + + def generate_destruction_report(self, file: IO) -> None: + workbook = xlsxwriter.Workbook(file.name, options={"in_memory": False}) + + worksheet = workbook.add_worksheet(name=gettext("Deleted zaken")) + + self.add_zaken_table(worksheet) + + workbook.close() diff --git a/backend/src/openarchiefbeheer/destruction/models.py b/backend/src/openarchiefbeheer/destruction/models.py index d486233e..427d73de 100644 --- a/backend/src/openarchiefbeheer/destruction/models.py +++ b/backend/src/openarchiefbeheer/destruction/models.py @@ -10,9 +10,8 @@ from django.db import models from django.db.models import QuerySet from django.utils import timezone -from django.utils.translation import gettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ -import xlsxwriter from privates.fields import PrivateMediaFileField from slugify import slugify from timeline_logger.models import TimelineLog @@ -220,49 +219,17 @@ def abort_destruction(self) -> None: self.save() def generate_destruction_report(self) -> None: + from .destruction_report import DestructionReportGenerator + if not self.status == ListStatus.deleted: logger.warning("The destruction list has not been deleted yet.") return - fieldnames = [ - "url", - "einddatum", - "resultaat", - "startdatum", - "omschrijving", - "identificatie", - "zaaktype url", - "zaaktype omschrijving", - "selectielijst procestype nummer", - ] + generator = DestructionReportGenerator(destruction_list=self) with NamedTemporaryFile(mode="wb", delete_on_close=False) as f_tmp: - workbook = xlsxwriter.Workbook(f_tmp.name, options={"in_memory": False}) - worksheet = workbook.add_worksheet(name=gettext("Deleted zaken")) - worksheet.write_row(0, 0, fieldnames) - - for row_count, item in enumerate( - self.items.filter(processing_status=InternalStatus.succeeded).iterator( - chunk_size=1000 - ) - ): - data = [ - item.extra_zaak_data["url"], - item.extra_zaak_data["einddatum"], - item.extra_zaak_data["resultaat"], - item.extra_zaak_data["startdatum"], - item.extra_zaak_data["omschrijving"], - item.extra_zaak_data["identificatie"], - item.extra_zaak_data["zaaktype"]["url"], - item.extra_zaak_data["zaaktype"]["omschrijving"], - item.extra_zaak_data["zaaktype"]["selectielijst_procestype"][ - "nummer" - ], - ] - - worksheet.write_row(row_count + 1, 0, data) - workbook.close() - + generator.generate_destruction_report(f_tmp) f_tmp.close() + with open(f_tmp.name, mode="rb") as f: django_file = File(f) self.destruction_report.save( diff --git a/backend/src/openarchiefbeheer/zaken/api/constants.py b/backend/src/openarchiefbeheer/zaken/api/constants.py new file mode 100644 index 00000000..b121bdee --- /dev/null +++ b/backend/src/openarchiefbeheer/zaken/api/constants.py @@ -0,0 +1,15 @@ +# The structure of ZAAK_METADATA_FIELDS_MAPPINGS needs to remain in sync with ZaakMetadataSerializer +ZAAK_METADATA_FIELDS_MAPPINGS = [ + {"name": "url", "path": "url"}, + {"name": "einddatum", "path": "einddatum"}, + {"name": "resultaat", "path": "resultaat"}, + {"name": "startdatum", "path": "startdatum"}, + {"name": "omschrijving", "path": "omschrijving"}, + {"name": "identificatie", "path": "identificatie"}, + {"name": "zaaktype url", "path": "zaaktype.url"}, + {"name": "zaaktype omschrijving", "path": "zaaktype.omschrijving"}, + { + "name": "selectielijst procestype nummer", + "path": "zaaktype.selectielijst_procestype.nummer", + }, +] diff --git a/backend/src/openarchiefbeheer/zaken/api/serializers.py b/backend/src/openarchiefbeheer/zaken/api/serializers.py index 7e702013..7fe68936 100644 --- a/backend/src/openarchiefbeheer/zaken/api/serializers.py +++ b/backend/src/openarchiefbeheer/zaken/api/serializers.py @@ -76,6 +76,8 @@ class SelectielijstklasseChoicesQueryParamSerializer(serializers.Serializer): ) +# The structure of ZaakMetadataSerializer needs to remain in sync with ZAAK_METADATA_FIELDS_MAPPINGS +# TODO: Make more robust so that we don't have to worry about keeping in sync class ZaakMetadataSerializer(serializers.ModelSerializer): zaaktype = serializers.SerializerMethodField()