From 1f9bc7699aa68e8481b6b073db8b218e955bb194 Mon Sep 17 00:00:00 2001
From: Neda Moeini <neda.moeini@geant.org>
Date: Tue, 11 Feb 2025 10:15:40 +0100
Subject: [PATCH] Update nc_cc_dep_combination_against_meo_sage_account
 validation to cover the all the repetitive parts.

---
 sage_validation/file_validator/forms.py | 69 ++++++++++++++-----------
 1 file changed, 40 insertions(+), 29 deletions(-)

diff --git a/sage_validation/file_validator/forms.py b/sage_validation/file_validator/forms.py
index 6413434..0e22efe 100644
--- a/sage_validation/file_validator/forms.py
+++ b/sage_validation/file_validator/forms.py
@@ -7,7 +7,8 @@ from typing import ClassVar
 from django import forms
 from django.core.files.uploadedfile import UploadedFile
 
-from sage_validation.file_validator.models import MeoCostCentres, MeoValidSageAccounts, XxData, MeoValidSuppliers
+from sage_validation.file_validator.models import MeoCostCentres, MeoValidSageAccounts, XxData, MeoValidSuppliers, \
+    MeoNominal
 
 
 class CSVUploadForm(forms.Form):
@@ -72,7 +73,6 @@ class CSVUploadForm(forms.Form):
         self._validate_headers(fieldnames)
 
         error_list = []
-        # Step 3: Validate 'Source' and 'SYSTraderTranType' values
         data = list(reader)
         error_list.extend(self._validate_source_and_trader_type(data))
         error_list.extend(self._validate_nominal_analysis_account(data))
@@ -174,16 +174,16 @@ class CSVUploadForm(forms.Form):
 
         return errors
 
-    @staticmethod
-    def _validate_nc_cc_dep_combination_against_meo_sage_account(data: Iterable[dict]) -> list[str]:
-        """Validate that the combination of 'AccountCostCentre', 'AccountDepartment', and 'AccountNumber' exists in MEO.
+
+    def _validate_nc_cc_dep_combination_against_meo_sage_account(self, data: Iterable[dict]) -> list[str]:
+        """Validate that all occurrences of 'NominalAnalysisNominalCostCentre/{N}',
+        'NominalAnalysisNominalDepartment/{N}', and 'NominalAnalysisNominalAccountNumber/{N}' exist in MEO.
 
         Args:
             data (Iterable[dict]): The rows of data to validate.
 
         Returns:
             List[str]: A list of error messages, if any.
-
         """
         errors = []
 
@@ -195,34 +195,45 @@ class CSVUploadForm(forms.Form):
             obj.xx_value: (obj.project, obj.overhead) for obj in XxData.objects.using("meo").all()
         }
 
+
+        fieldnames = list(data[0].keys())
+        max_repeat = self._get_max_repeat(fieldnames, "NominalAnalysisNominalCostCentre")
+
         for index, row in enumerate(data, start=1):
-            cc = row.get("NominalAnalysisNominalCostCentre/1")
-            dep = row.get("NominalAnalysisNominalDepartment/1")
-            nominal_account_name = row.get("NominalAnalysisNominalAccountNumber/1")
+            for repeat in range(1, max_repeat + 1):
+                cc_field = f"NominalAnalysisNominalCostCentre/{repeat}"
+                dep_field = f"NominalAnalysisNominalDepartment/{repeat}"
+                nominal_account_field = f"NominalAnalysisNominalAccountNumber/{repeat}"
 
-            if not cc or not dep or not nominal_account_name:
-                continue
+                cc = row.get(cc_field)
+                dep = row.get(dep_field)
+                nominal_account_name = row.get(nominal_account_field)
 
-            cc_type = cost_centre_map.get(cc)
-            if not cc_type:
-                errors.append(f"Row {index}: 'NominalAnalysisNominalCostCentre/1' ({cc}) is not a valid cost centre.")
-                continue
+                if not cc or not dep or not nominal_account_name:
+                    continue
 
-            xx_data = xx_data_map.get(nominal_account_name)
-            if not xx_data:
-                errors.append(
-                    f"Row {index}: 'NominalAnalysisNominalAccountNumber/1' ({nominal_account_name}) is not valid.")
-                continue
+                cc_type = cost_centre_map.get(cc)
+                if not cc_type:
+                    errors.append(f"Row {index}: '{cc_field}' ({cc}) is not a valid cost centre.")
+                    continue
 
-            nc = xx_data[0] if cc_type == "Project" else xx_data[1]
+                xx_data = xx_data_map.get(nominal_account_name)
 
-            if not MeoValidSageAccounts.objects.using("meo").filter(
-                    account_cost_centre=cc, account_department=dep, account_number=nc
-            ).exists():
-                errors.append(
-                    f"Row {index}: The combination of 'NominalAnalysisNominalCostCentre/1' ({cc}), "
-                    f"'NominalAnalysisNominalDepartment/1' ({dep}), and 'NominalAnalysisNominalAccountNumber/1' "
-                    f"({nominal_account_name}) does not exist in MEO valid Sage accounts."
-                )
+                if xx_data:
+                    nc = xx_data[0] if cc_type == "Project" else xx_data[1]
+                elif MeoNominal.objects.using("meo").filter(nom=nominal_account_name).exists():
+                    nc = nominal_account_name
+                else:
+                    errors.append(f"Row {index}: '{nominal_account_field}' ({nominal_account_name}) is not valid.")
+                    continue
+
+                if not MeoValidSageAccounts.objects.using("meo").filter(
+                        account_cost_centre=cc, account_department=dep, account_number=nc
+                ).exists():
+                    errors.append(
+                        f"Row {index}: The combination of '{cc_field}' ({cc}), "
+                        f"'{dep_field}' ({dep}), and '{nominal_account_field}' "
+                        f"({nominal_account_name}) does not exist in MEO valid Sage accounts."
+                    )
 
         return errors
-- 
GitLab