Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/mappings/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
from apps.fyle.models import DependentFieldSetting
from fyle_integrations_imports.models import ImportLog
from fyle_integrations_imports.dataclasses import TaskSetting
from apps.sage_intacct.helpers import get_sage_intacct_connection
from apps.sage_intacct.enums import SageIntacctRestConnectionTypeEnum
from fyle_intacct_api.utils import invalidate_sage_intacct_credentials
from fyle_integrations_imports.queues import chain_import_fields_to_fyle
from workers.helpers import RoutingKeyEnum, WorkerActionEnum, publish_to_rabbitmq
from apps.sage_intacct.helpers import get_sage_intacct_connection, validate_rest_api_connection
from apps.mappings.helpers import get_project_billable_field_detail_key, is_project_billable_sync_allowed
from apps.workspaces.models import (
Configuration,
Expand Down Expand Up @@ -306,6 +306,7 @@ def initiate_import_to_fyle(workspace_id: int, run_in_rabbitmq_worker: bool = Fa
:param workspace_id: Workspace Id
:return: None
"""
validate_rest_api_connection(workspace_id=workspace_id)
mapping_settings = MappingSetting.objects.filter(workspace_id=workspace_id, import_to_fyle=True)
configuration = Configuration.objects.get(workspace_id=workspace_id)
dependent_fields = DependentFieldSetting.objects.filter(workspace_id=workspace_id, is_import_enabled=True).first()
Expand Down
23 changes: 23 additions & 0 deletions apps/sage_intacct/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def check_interval_and_sync_dimension(workspace_id: int, **kwargs) -> bool:
"""
workspace = Workspace.objects.get(pk=workspace_id)
try:
validate_rest_api_connection(workspace_id=workspace_id)
if workspace.destination_synced_at:
time_interval = datetime.now(timezone.utc) - workspace.source_synced_at

Expand Down Expand Up @@ -137,3 +138,25 @@ def sync_dimensions(workspace_id: int, dimensions: list = []) -> None:

workspace.destination_synced_at = datetime.now()
workspace.save(update_fields=['destination_synced_at'])


def validate_rest_api_connection(workspace_id: int) -> None:
"""
Validate REST API connection for orgs and migrated them to rest api
:param workspace_id: Workspace ID
:return: None
"""
migrated_to_rest_api = FeatureConfig.get_feature_config(workspace_id=workspace_id, key='migrated_to_rest_api')
if migrated_to_rest_api:
return

try:
sage_intacct_connection = SageIntacctRestConnector(workspace_id=workspace_id)
sage_intacct_connection.connection.locations.count()
FeatureConfig.objects.filter(workspace_id=workspace_id, migrated_to_rest_api=False).update(
migrated_to_rest_api=True,
updated_at=datetime.now(timezone.utc)
)
sync_dimensions(workspace_id=workspace_id)
except Exception as e:
logger.info('REST API is not working for workspace_id - %s, error - %s', workspace_id, e)
81 changes: 80 additions & 1 deletion tests/test_sageintacct/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
check_interval_and_sync_dimension,
is_dependent_field_import_enabled,
schedule_payment_sync,
validate_rest_api_connection
)
from apps.sage_intacct.exports.helpers import get_source_entity_id
from apps.sage_intacct.exports.journal_entries import construct_journal_entry_payload
from apps.fyle.models import ExpenseGroup
from apps.mappings.models import GeneralMapping, LocationEntityMapping
from apps.workspaces.models import Configuration, FyleCredential, Workspace
from apps.workspaces.models import Configuration, FyleCredential, Workspace, FeatureConfig
from apps.workspaces.tasks import patch_integration_settings


Expand Down Expand Up @@ -194,3 +195,81 @@ def test_construct_journal_entry_payload_with_source_entity(db, mocker, create_j

assert 'baseLocation' in payload
assert payload['baseLocation']['id'] == 'LOC123'


def test_validate_rest_api_connection_already_migrated(db, mocker):
"""
Test validate_rest_api_connection when already migrated to REST API
Should return early without attempting connection
"""
workspace_id = 1

mocker.patch('apps.sage_intacct.helpers.FeatureConfig.get_feature_config', return_value=True)
mock_connector = mocker.patch('apps.sage_intacct.helpers.SageIntacctRestConnector')
mock_sync_dimensions = mocker.patch('apps.sage_intacct.helpers.sync_dimensions')

validate_rest_api_connection(workspace_id)

mock_connector.assert_not_called()
mock_sync_dimensions.assert_not_called()


def test_validate_rest_api_connection_successful_migration(db, mocker):
"""
Test validate_rest_api_connection when REST API connection is successful
Should update FeatureConfig and call sync_dimensions
"""
workspace_id = 1

feature_config = FeatureConfig.objects.get(workspace_id=workspace_id)
feature_config.migrated_to_rest_api = False
feature_config.save()

mocker.patch('apps.sage_intacct.helpers.FeatureConfig.get_feature_config', return_value=False)

mock_connector_instance = mocker.Mock()
mock_connector_instance.connection.locations.count.return_value = 10
mock_connector = mocker.patch('apps.sage_intacct.helpers.SageIntacctRestConnector', return_value=mock_connector_instance)
mock_sync_dimensions = mocker.patch('apps.sage_intacct.helpers.sync_dimensions')

validate_rest_api_connection(workspace_id)

mock_connector.assert_called_once_with(workspace_id=workspace_id)
mock_connector_instance.connection.locations.count.assert_called_once()
mock_sync_dimensions.assert_called_once_with(workspace_id=workspace_id)

feature_config.refresh_from_db()
assert feature_config.migrated_to_rest_api is True


def test_validate_rest_api_connection_failed_connection(db, mocker):
"""
Test validate_rest_api_connection when REST API connection fails
Should log error and not update FeatureConfig
"""
workspace_id = 1

feature_config = FeatureConfig.objects.get(workspace_id=workspace_id)
feature_config.migrated_to_rest_api = False
feature_config.save()

mocker.patch('apps.sage_intacct.helpers.FeatureConfig.get_feature_config', return_value=False)

mock_connector_instance = mocker.Mock()
mock_connector_instance.connection.locations.count.side_effect = Exception('Connection failed')
mock_connector = mocker.patch('apps.sage_intacct.helpers.SageIntacctRestConnector', return_value=mock_connector_instance)
mock_sync_dimensions = mocker.patch('apps.sage_intacct.helpers.sync_dimensions')
logger_mock = mocker.patch('apps.sage_intacct.helpers.logger')

validate_rest_api_connection(workspace_id)

mock_connector.assert_called_once_with(workspace_id=workspace_id)
mock_connector_instance.connection.locations.count.assert_called_once()
mock_sync_dimensions.assert_not_called()
logger_mock.info.assert_called_once()
call_args = logger_mock.info.call_args[0]
assert 'REST API is not working' in call_args[0]
assert str(workspace_id) in str(call_args)

feature_config.refresh_from_db()
assert feature_config.migrated_to_rest_api is False
Loading