diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000000000000000000000000000000000..8872a16fd5a9bca02b90790265e49af543cb3837 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +DJANGO_SETTINGS_MODULE = test.settings +django_find_project = false +python_files = tests.py test_*.py *_tests.py \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 0fb6979ad1f0d490d1ea74e2384a40dd911b001c..af546b5715aff459e499561326471c5df26c8eaa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,7 @@ tox sphinx sphinx-autodoc-typehints mssql-django +pytest +pytest-django +pytest-mock +faker diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..1d75fae72ef188e045214a71f681f02d917eac19 --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,132 @@ +import pytest +from unittest.mock import MagicMock +from django.core.files.uploadedfile import SimpleUploadedFile +from sage_validation.file_validator.models import MeoValidSuppliers, MeoCostCentres, XxData +from faker import Faker + + +@pytest.fixture +def sample_input_file(): + """Creates a sample valid CSV file for testing.""" + csv_headers = ",".join([ + "AccountNumber", + "CBAccountNumber", + "DaysDiscountValid", + "DiscountValue", + "DiscountPercentage", + "DueDate", + "GoodsValueInAccountCurrency", + "PurControlValueInBaseCurrency", + "DocumentToBaseCurrencyRate", + "DocumentToAccountCurrencyRate", + "PostedDate", + "QueryCode", + "TransactionReference", + "SecondReference", + "Source", + "SYSTraderTranType", + "TransactionDate", + "UniqueReferenceNumber", + "UserNumber", + "TaxValue", + "SYSTraderGenerationReasonType", + "GoodsValueInBaseCurrency", + + # NominalAnalysis repeating columns (Example: /1 for first occurrence) + "NominalAnalysisTransactionValue/1", + "NominalAnalysisNominalAccountNumber/1", + "NominalAnalysisNominalCostCentre/1", + "NominalAnalysisNominalDepartment/1", + "NominalAnalysisNominalAnalysisNarrative/1", + "NominalAnalysisTransactionAnalysisCode/1", + + # TaxAnalysis repeating columns (Example: /1 for first occurrence) + "TaxAnalysisTaxRate/1", + "TaxAnalysisGoodsValueBeforeDiscount/1", + "TaxAnalysisDiscountValue/1", + "TaxAnalysisDiscountPercentage/1", + "TaxAnalysisTaxOnGoodsValue/1", + ]) + + csv_content = ",".join([ + "12345", # AccountNumber + "54321", # CBAccountNumber + "30", # DaysDiscountValid + "10.5", # DiscountValue + "5.0", # DiscountPercentage + "2024-02-10", # DueDate + "1000", # GoodsValueInAccountCurrency + "950", # PurControlValueInBaseCurrency + "1.2", # DocumentToBaseCurrencyRate + "1.1", # DocumentToAccountCurrencyRate + "2024-02-05", # PostedDate + "Q1", # QueryCode + "TRX123", # TransactionReference + "SREF123", # SecondReference + "80", # Source + "4", # SYSTraderTranType + "2024-02-01", # TransactionDate + "UR123", # UniqueReferenceNumber + "42", # UserNumber + "10", # TaxValue + "1000", # SYSTraderGenerationReasonType + "1200", # GoodsValueInBaseCurrency + + # NominalAnalysis repeating values (Example: /1) + "500.75", # NominalAnalysisTransactionValue/1 + "ACC100", # NominalAnalysisNominalAccountNumber/1 + "CC100", # NominalAnalysisNominalCostCentre/1 + "DEP200", # NominalAnalysisNominalDepartment/1 + "Sample Narrative", # NominalAnalysisNominalAnalysisNarrative/1 + "TAC100", # NominalAnalysisTransactionAnalysisCode/1 + + # TaxAnalysis repeating values (Example: /1) + "20.5", # TaxAnalysisTaxRate/1 + "900", # TaxAnalysisGoodsValueBeforeDiscount/1 + "30", # TaxAnalysisDiscountValue/1 + "3.5", # TaxAnalysisDiscountPercentage/1 + "180", # TaxAnalysisTaxOnGoodsValue/1 + ]) + + return SimpleUploadedFile("test.csv", f"{csv_headers}\n{csv_content}".encode("utf-8"), content_type="text/csv") + +@pytest.fixture +def mock_meo_database(mocker): + """Mock the meo database since it's read-only.""" + fake = Faker() + + # Mock MeoValidSuppliers + supplier_mock = MagicMock() + supplier_mock.all.return_value = [ + MeoValidSuppliers(supplier_account_number=str(fake.random_int(min=10000, max=99999)), supplier_account_name=fake.company()), + MeoValidSuppliers(supplier_account_number="12345", supplier_account_name=fake.company()) + ] + mocker.patch("sage_validation.file_validator.models.MeoValidSuppliers.objects.using", return_value=supplier_mock) + + # Mock MeoCostCentres + cost_centre_mock = MagicMock() + cost_centre_mock.all.return_value = [ + MeoCostCentres(cc="CC100", cc_type="Project", cc_name="CostCentreName", id=1), + MeoCostCentres(cc="CC200", cc_type="Overhead", cc_name="OverheadName", id=2), + MeoCostCentres(cc="CC300", cc_type="Overhead", cc_name="DepartmentName", id=3) + ] + mocker.patch("sage_validation.file_validator.models.MeoCostCentres.objects.using", return_value=cost_centre_mock) + + # Mock XxData + xx_data_mock = MagicMock() + xx_data_mock.all.return_value = [ + XxData(xx_value="N100", project="ProjectCode", overhead="OverheadCode", description=fake.sentence()), + XxData(xx_value="N200", project="ProjectCode", overhead="OverheadCode", description=fake.sentence()) + ] + mocker.patch("sage_validation.file_validator.models.XxData.objects.using", return_value=xx_data_mock) + + # Mock MeoValidSageAccounts + sage_account_mock = MagicMock() + sage_account_mock.filter.return_value.exists.return_value = True + mocker.patch("sage_validation.file_validator.models.MeoValidSageAccounts.objects.using", return_value=sage_account_mock) + + # Mock MeoNominal + nominal_mock = MagicMock() + nominal_mock.filter.return_value.exists.return_value = True + mocker.patch("sage_validation.file_validator.models.MeoNominal.objects.using", return_value=nominal_mock) + diff --git a/test/settings.py b/test/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..a5690fba5fcce1551257e394d4f490910a0d9ce4 --- /dev/null +++ b/test/settings.py @@ -0,0 +1,5 @@ +from sage_validation.settings import * # noqa: F403, F401 + +DATABASES = { + "default": DATABASES["default"], +}