From 15881339b94b09fb19ecdece11b30fe334ee1a25 Mon Sep 17 00:00:00 2001
From: Neda Moeini <neda.moeini@geant.org>
Date: Mon, 27 Jan 2025 14:05:05 +0000
Subject: [PATCH] Validate that the combination of 'AccountCostCentre' and
 'AccountDepartment' and "AccountNumber"

---
 sage_validation/file_validator/forms.py | 62 +++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 4 deletions(-)

diff --git a/sage_validation/file_validator/forms.py b/sage_validation/file_validator/forms.py
index 0442892..a8c43ea 100644
--- a/sage_validation/file_validator/forms.py
+++ b/sage_validation/file_validator/forms.py
@@ -7,7 +7,7 @@ from typing import ClassVar
 from django import forms
 from django.core.files.uploadedfile import UploadedFile
 
-from sage_validation.file_validator.models import PlAccountCodes
+from sage_validation.file_validator.models import Meocostcentres, Meovalidsageaccounts, PlAccountCodes, XxData
 
 
 class CSVUploadForm(forms.Form):
@@ -76,6 +76,7 @@ class CSVUploadForm(forms.Form):
         data = list(reader)
         error_list.extend(self._validate_source_and_trader_type(data))
         error_list.extend(self._validate_nominal_analysis_account(data))
+        error_list.extend(self._validate_nc_cc_dep_combination_against_meo_sage_account(data))
         if error_list:
             raise forms.ValidationError(error_list)
 
@@ -135,8 +136,7 @@ class CSVUploadForm(forms.Form):
 
     @staticmethod
     def _validate_nominal_analysis_account(data: Iterable[dict]) -> list[str]:
-        """
-        Validate that 'AccountNumber' matches the name in 'NominalAnalysisNominalAnalysisNarrative/1'.
+        """Validate that 'AccountNumber' matches the name in 'NominalAnalysisNominalAnalysisNarrative/1'.
 
         This only checks the first group of NominalAnalysis columns. A list of codes/names
         is fetched from the database for validation (from the 'PL Account Codes' table).
@@ -146,6 +146,7 @@ class CSVUploadForm(forms.Form):
 
         Returns:
             List[str]: A list of error messages, if any.
+
         """
         errors = []
 
@@ -171,4 +172,57 @@ class CSVUploadForm(forms.Form):
                     f"'NominalAnalysisNominalAnalysisNarrative/1', but found '{nominal}'."
                 )
 
-        return errors
\ No newline at end of file
+        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.
+
+        Args:
+            data (Iterable[dict]): The rows of data to validate.
+
+        Returns:
+            List[str]: A list of error messages, if any.
+
+        """
+        errors = []
+
+        cost_centre_map = {
+            obj.cc: obj.cctype for obj in Meocostcentres.objects.using("meo").all()
+        }
+
+        xx_data_map = {
+            obj.xx_value: (obj.project, obj.overhead) for obj in XxData.objects.using("meo").all()
+        }
+
+        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")
+
+            if not cc or not dep or not nominal_account_name:
+                continue
+
+            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
+
+            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
+
+            nc = xx_data[0] if cc_type == "Project" else xx_data[1]
+
+            if not Meovalidsageaccounts.objects.using("meo").filter(
+                    accountcostcentre=cc, accountdepartment=dep, accountnumber=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."
+                )
+
+        return errors
-- 
GitLab