From 3a35a6baa2b0a5c6eb5bc4512effa1f3e4fb186a Mon Sep 17 00:00:00 2001 From: Ashutosh singh <55102089+Ashutosh619-sudo@users.noreply.github.com> Date: Mon, 28 Aug 2023 13:32:57 +0530 Subject: [PATCH] moving views logic to actions (#255) * moving views logic to actions * indentation issue resolved --------- Co-authored-by: Ashutosh619-sudo --- apps/fyle/actions.py | 75 +++++++++++++++ apps/fyle/views.py | 68 ++----------- apps/mappings/actions.py | 48 ++++++++++ apps/mappings/views.py | 39 +------- apps/workspaces/actions.py | 142 ++++++++++++++++++++++++++++ apps/workspaces/views.py | 131 ++----------------------- apps/xero/actions.py | 61 ++++++++++++ apps/xero/views.py | 68 ++----------- tests/test_workspaces/test_views.py | 10 +- 9 files changed, 361 insertions(+), 281 deletions(-) create mode 100644 apps/fyle/actions.py create mode 100644 apps/mappings/actions.py create mode 100644 apps/workspaces/actions.py create mode 100644 apps/xero/actions.py diff --git a/apps/fyle/actions.py b/apps/fyle/actions.py new file mode 100644 index 00000000..9d3501c6 --- /dev/null +++ b/apps/fyle/actions.py @@ -0,0 +1,75 @@ +from fyle_accounting_mappings.models import ExpenseAttribute +from django.db.models import Q + +from apps.tasks.models import TaskLog +from apps.workspaces.models import FyleCredential, WorkspaceGeneralSettings, Workspace +from apps.workspaces.serializers import WorkspaceSerializer +from datetime import datetime, timezone +from .models import Expense, ExpenseGroup, ExpenseGroupSettings + +from fyle_integrations_platform_connector import PlatformConnector + +def get_expense_field(workspace_id): + + default_attributes = ['EMPLOYEE', 'CATEGORY', 'PROJECT', 'COST_CENTER', 'CORPORATE_CARD', 'TAX_GROUP'] + attributes = ExpenseAttribute.objects.filter( + ~Q(attribute_type__in=default_attributes), + workspace_id=workspace_id + ).values('attribute_type', 'display_name').distinct() + + expense_fields= [ + {'attribute_type': 'COST_CENTER', 'display_name': 'Cost Center'}, + {'attribute_type': 'PROJECT', 'display_name': 'Project'} + ] + + for attribute in attributes: + expense_fields.append(attribute) + + return expense_fields + + +def sync_fyle_dimension(workspace_id): + + workspace = Workspace.objects.get(id=workspace_id) + if workspace.source_synced_at: + time_interval = datetime.now(timezone.utc) - workspace.source_synced_at + + if workspace.source_synced_at is None or time_interval.days > 0: + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + + platform = PlatformConnector(fyle_credentials) + platform.import_fyle_dimensions() + + workspace.source_synced_at = datetime.now() + workspace.save(update_fields=['source_synced_at']) + + +def refresh_fyle_dimension(workspace_id): + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + + platform = PlatformConnector(fyle_credentials) + platform.import_fyle_dimensions() + + workspace = Workspace.objects.get(id=workspace_id) + workspace.source_synced_at = datetime.now() + workspace.save(update_fields=['source_synced_at']) + + +def exportable_expense_group(workspace_id): + + configuration = WorkspaceGeneralSettings.objects.get(workspace_id=workspace_id) + fund_source = [] + + if configuration.reimbursable_expenses_object: + fund_source.append('PERSONAL') + if configuration.corporate_credit_card_expenses_object: + fund_source.append('CCC') + + expense_group_ids = ExpenseGroup.objects.filter( + workspace_id=workspace_id, + exported_at__isnull=True, + fund_source__in=fund_source + ).values_list('id', flat=True) + + return expense_group_ids diff --git a/apps/fyle/views.py b/apps/fyle/views.py index c3c3a63f..6cfea352 100644 --- a/apps/fyle/views.py +++ b/apps/fyle/views.py @@ -1,25 +1,13 @@ -from datetime import datetime, timezone -from django.db.models import Q - from rest_framework.views import status from rest_framework import generics from rest_framework.response import Response -from fyle_accounting_mappings.models import ExpenseAttribute -from fyle_accounting_mappings.serializers import ExpenseAttributeSerializer - -from fyle_integrations_platform_connector import PlatformConnector - -from apps.tasks.models import TaskLog -from apps.workspaces.models import FyleCredential, WorkspaceGeneralSettings, Workspace -from apps.workspaces.serializers import WorkspaceSerializer - -from fyle_integrations_platform_connector import PlatformConnector -from .tasks import create_expense_groups, get_task_log_and_fund_source, async_create_expense_groups +from .tasks import get_task_log_and_fund_source, async_create_expense_groups from .models import Expense, ExpenseGroup, ExpenseGroupSettings -from .serializers import ExpenseGroupSerializer, ExpenseSerializer, ExpenseFieldSerializer, \ +from .serializers import ExpenseGroupSerializer, ExpenseFieldSerializer, \ ExpenseGroupSettingsSerializer from apps.exceptions import handle_view_exceptions +from .actions import exportable_expense_group, get_expense_field, refresh_fyle_dimension, sync_fyle_dimension class ExpenseGroupView(generics.ListCreateAPIView): @@ -98,19 +86,8 @@ class ExpenseFieldsView(generics.ListAPIView): serializer_class = ExpenseFieldSerializer def get(self, request, *args, **kwargs): - default_attributes = ['EMPLOYEE', 'CATEGORY', 'PROJECT', 'COST_CENTER', 'CORPORATE_CARD', 'TAX_GROUP'] - attributes = ExpenseAttribute.objects.filter( - ~Q(attribute_type__in=default_attributes), - workspace_id=self.kwargs['workspace_id'] - ).values('attribute_type', 'display_name').distinct() - - expense_fields= [ - {'attribute_type': 'COST_CENTER', 'display_name': 'Cost Center'}, - {'attribute_type': 'PROJECT', 'display_name': 'Project'} - ] - for attribute in attributes: - expense_fields.append(attribute) + expense_fields = get_expense_field(workspace_id=kwargs['workspace_id']) return Response( expense_fields, @@ -146,18 +123,7 @@ def post(self, request, *args, **kwargs): Sync Data From Fyle """ - workspace = Workspace.objects.get(id=kwargs['workspace_id']) - if workspace.source_synced_at: - time_interval = datetime.now(timezone.utc) - workspace.source_synced_at - - if workspace.source_synced_at is None or time_interval.days > 0: - fyle_credentials = FyleCredential.objects.get(workspace_id=kwargs['workspace_id']) - - platform = PlatformConnector(fyle_credentials) - platform.import_fyle_dimensions() - - workspace.source_synced_at = datetime.now() - workspace.save(update_fields=['source_synced_at']) + sync_fyle_dimension(workspace_id=kwargs['workspace_id']) return Response( status=status.HTTP_200_OK @@ -174,15 +140,8 @@ def post(self, request, *args, **kwargs): """ Sync data from Fyle """ - - fyle_credentials = FyleCredential.objects.get(workspace_id=kwargs['workspace_id']) - - platform = PlatformConnector(fyle_credentials) - platform.import_fyle_dimensions() - workspace = Workspace.objects.get(id=kwargs['workspace_id']) - workspace.source_synced_at = datetime.now() - workspace.save(update_fields=['source_synced_at']) + refresh_fyle_dimension(workspace_id=kwargs['workspace_id']) return Response( status=status.HTTP_200_OK @@ -194,19 +153,8 @@ class ExportableExpenseGroupsView(generics.RetrieveAPIView): List Exportable Expense Groups """ def get(self, request, *args, **kwargs): - configuration = WorkspaceGeneralSettings.objects.get(workspace_id=kwargs['workspace_id']) - fund_source = [] - - if configuration.reimbursable_expenses_object: - fund_source.append('PERSONAL') - if configuration.corporate_credit_card_expenses_object: - fund_source.append('CCC') - - expense_group_ids = ExpenseGroup.objects.filter( - workspace_id=self.kwargs['workspace_id'], - exported_at__isnull=True, - fund_source__in=fund_source - ).values_list('id', flat=True) + + expense_group_ids = exportable_expense_group(workspace_id=kwargs['workspace_id']) return Response( data={'exportable_expense_group_ids': expense_group_ids}, diff --git a/apps/mappings/actions.py b/apps/mappings/actions.py new file mode 100644 index 00000000..29facada --- /dev/null +++ b/apps/mappings/actions.py @@ -0,0 +1,48 @@ +import logging +from .serializers import TenantMappingSerializer, GeneralMappingSerializer +from .models import TenantMapping, GeneralMapping +from apps.workspaces.models import XeroCredentials +from apps.xero.utils import XeroConnector +from apps.workspaces.models import Workspace +from ..workspaces.models import WorkspaceGeneralSettings + +from django_q.tasks import Chain + +from xerosdk.exceptions import UnsuccessfulAuthentication + +from .utils import MappingUtils + + +logger = logging.getLogger(__name__) + +def tenant_mapping_view(workspace_id, tenant_mapping_payload): + + mapping_utils = MappingUtils(workspace_id) + tenant_mapping_object = mapping_utils.create_or_update_tenant_mapping(tenant_mapping_payload) + xero_credentials = XeroCredentials.objects.filter(workspace_id=workspace_id).first() + workspace = Workspace.objects.filter(id=workspace_id).first() + + try: + xero_connector = XeroConnector(xero_credentials, workspace_id=workspace_id) + tenant_mapping = TenantMapping.objects.filter(workspace_id=workspace_id).first() + company_info = xero_connector.get_organisations()[0] + workspace.xero_currency = company_info['BaseCurrency'] + workspace.save() + xero_credentials.country = company_info['CountryCode'] + xero_credentials.save() + + if tenant_mapping and not tenant_mapping.connection_id: + connections = xero_connector.connection.connections.get_all() + connection = list(filter(lambda connection: connection['tenantId'] == tenant_mapping.tenant_id, connections)) + + if connection: + tenant_mapping.connection_id = connection[0]['id'] + tenant_mapping.save() + + except UnsuccessfulAuthentication: + logger.info('Xero refresh token is invalid for workspace_id - %s', workspace_id) + + except Exception: + logger.info('Error while fetching company information') + + return tenant_mapping_object diff --git a/apps/mappings/views.py b/apps/mappings/views.py index ce7a3354..1fc6e97b 100644 --- a/apps/mappings/views.py +++ b/apps/mappings/views.py @@ -7,16 +7,11 @@ from fyle_xero_api.utils import assert_valid -from xerosdk.exceptions import UnsuccessfulAuthentication - -from .serializers import TenantMappingSerializer, GeneralMappingSerializer -from .models import TenantMapping, GeneralMapping -from apps.workspaces.models import XeroCredentials -from .utils import MappingUtils +from .serializers import TenantMappingSerializer +from .models import TenantMapping from ..workspaces.models import WorkspaceGeneralSettings -from apps.xero.utils import XeroConnector -from apps.workspaces.models import Workspace from apps.exceptions import handle_view_exceptions +from .actions import tenant_mapping_view logger = logging.getLogger(__name__) @@ -35,33 +30,7 @@ def post(self, request, *args, **kwargs): assert_valid(tenant_mapping_payload is not None, 'Request body is empty') - mapping_utils = MappingUtils(kwargs['workspace_id']) - tenant_mapping_object = mapping_utils.create_or_update_tenant_mapping(tenant_mapping_payload) - xero_credentials = XeroCredentials.objects.filter(workspace_id=kwargs['workspace_id']).first() - workspace = Workspace.objects.filter(id=kwargs['workspace_id']).first() - - try: - xero_connector = XeroConnector(xero_credentials, workspace_id=kwargs['workspace_id']) - tenant_mapping = TenantMapping.objects.filter(workspace_id=kwargs['workspace_id']).first() - company_info = xero_connector.get_organisations()[0] - workspace.xero_currency = company_info['BaseCurrency'] - workspace.save() - xero_credentials.country = company_info['CountryCode'] - xero_credentials.save() - - if tenant_mapping and not tenant_mapping.connection_id: - connections = xero_connector.connection.connections.get_all() - connection = list(filter(lambda connection: connection['tenantId'] == tenant_mapping.tenant_id, connections)) - - if connection: - tenant_mapping.connection_id = connection[0]['id'] - tenant_mapping.save() - - except UnsuccessfulAuthentication: - logger.info('Xero refresh token is invalid for workspace_id - %s', kwargs['workspace_id']) - - except Exception: - logger.info('Error while fetching company information') + tenant_mapping_object = tenant_mapping_view(workspace_id=kwargs['workspace_id'],tenant_mapping_payload=tenant_mapping_payload) return Response( data=self.serializer_class(tenant_mapping_object).data, diff --git a/apps/workspaces/actions.py b/apps/workspaces/actions.py new file mode 100644 index 00000000..159ae7b0 --- /dev/null +++ b/apps/workspaces/actions.py @@ -0,0 +1,142 @@ +import logging +from fyle_rest_auth.helpers import get_fyle_admin +from .models import Workspace +from django.contrib.auth import get_user_model +from apps.fyle.models import ExpenseGroupSettings +from .models import Workspace, FyleCredential, XeroCredentials, WorkspaceGeneralSettings, WorkspaceSchedule, LastExportDetail +from django.core.cache import cache +from apps.fyle.helpers import get_cluster_domain +from fyle_rest_auth.models import AuthToken +from django_q.tasks import async_task +from apps.mappings.models import TenantMapping +from apps.xero.utils import XeroConnector + +from xerosdk import exceptions as xero_exc + +from .utils import generate_xero_refresh_token +from apps.workspaces.signals import post_delete_xero_connection + +from apps.fyle.models import ExpenseGroupSettings +from fyle_accounting_mappings.models import ExpenseAttribute + +logger = logging.getLogger(__name__) + +def post_workspace(access_token,request): + + fyle_user = get_fyle_admin(access_token.split(' ')[1], None) + org_name = fyle_user['data']['org']['name'] + org_id = fyle_user['data']['org']['id'] + fyle_currency = fyle_user['data']['org']['currency'] + User = get_user_model() + + workspace = Workspace.objects.filter(fyle_org_id=org_id).first() + + if workspace: + workspace.user.add(User.objects.get(user_id=request.user)) + cache.delete(str(workspace.id)) + else: + workspace = Workspace.objects.create(name=org_name, fyle_currency=fyle_currency, fyle_org_id=org_id) + + ExpenseGroupSettings.objects.create(workspace_id=workspace.id) + + LastExportDetail.objects.create(workspace_id=workspace.id) + + workspace.user.add(User.objects.get(user_id=request.user)) + + auth_tokens = AuthToken.objects.get(user__user_id=request.user) + + cluster_domain = get_cluster_domain(auth_tokens.refresh_token) + + FyleCredential.objects.update_or_create( + refresh_token=auth_tokens.refresh_token, + workspace_id=workspace.id, + cluster_domain=cluster_domain + ) + + async_task('apps.workspaces.tasks.async_add_admins_to_workspace', workspace.id, request.user.user_id) + + return workspace + +def connect_xero(authorization_code, redirect_uri, workspace_id): + + if redirect_uri: + refresh_token = generate_xero_refresh_token(authorization_code, redirect_uri) + else: + refresh_token = generate_xero_refresh_token(authorization_code) + xero_credentials = XeroCredentials.objects.filter(workspace_id=workspace_id).first() + tenant_mapping = TenantMapping.objects.filter(workspace_id=workspace_id).first() + + workspace = Workspace.objects.get(pk=workspace_id) + + if not xero_credentials: + xero_credentials = XeroCredentials.objects.create( + refresh_token=refresh_token, + workspace_id=workspace_id + ) + + else: + xero_credentials.refresh_token = refresh_token + xero_credentials.is_expired = False + xero_credentials.save() + + if tenant_mapping and not tenant_mapping.connection_id: + xero_connector = XeroConnector(xero_credentials, workspace_id=workspace_id) + connections = xero_connector.connection.connections.get_all() + connection = list(filter(lambda connection: connection['tenantId'] == tenant_mapping.tenant_id, connections)) + + if connection: + tenant_mapping.connection_id = connection[0]['id'] + tenant_mapping.save() + + if tenant_mapping: + try: + xero_connector = XeroConnector(xero_credentials, workspace_id=workspace_id) + company_info = xero_connector.get_organisations()[0] + workspace.xero_currency = company_info['BaseCurrency'] + workspace.save() + xero_credentials.country = company_info['CountryCode'] + xero_credentials.save() + except (xero_exc.WrongParamsError, xero_exc.UnsuccessfulAuthentication) as exception: + logger.info(exception.response) + + if workspace.onboarding_state == 'CONNECTION': + workspace.onboarding_state = 'EXPORT_SETTINGS' + workspace.save() + + return xero_credentials + +def revoke_connections(workspace_id): + + xero_credentials = XeroCredentials.objects.filter(workspace_id=workspace_id).first() + tenant_mapping = TenantMapping.objects.filter(workspace_id=workspace_id).first() + if xero_credentials: + if tenant_mapping and tenant_mapping.connection_id: + try: + xero_connector = XeroConnector(xero_credentials, workspace_id=workspace_id) + xero_connector.connection.connections.remove_connection(tenant_mapping.connection_id) + except (xero_exc.InvalidGrant, xero_exc.UnsupportedGrantType, + xero_exc.InvalidTokenError, xero_exc.UnsuccessfulAuthentication, + xero_exc.WrongParamsError, xero_exc.NoPrivilegeError, + xero_exc.InternalServerError): + pass + + xero_credentials.refresh_token = None + xero_credentials.country = None + xero_credentials.is_expired = True + xero_credentials.save() + + post_delete_xero_connection(workspace_id) + +def get_workspace_admin(workspace_id): + + workspace = Workspace.objects.get(pk=workspace_id) + User = get_user_model() + + admin_email = [] + users = workspace.user.all() + for user in users: + admin = User.objects.get(user_id=user) + employee = ExpenseAttribute.objects.filter(value=admin.email, workspace_id=workspace_id, attribute_type='EMPLOYEE').first() + if employee: + admin_email.append({'name': employee.detail['full_name'], 'email': admin.email}) + return admin_email diff --git a/apps/workspaces/views.py b/apps/workspaces/views.py index 44ad002a..1f3e2de3 100644 --- a/apps/workspaces/views.py +++ b/apps/workspaces/views.py @@ -1,39 +1,23 @@ -import json import logging from django.contrib.auth import get_user_model -from django.core.cache import cache - -from django_q.tasks import async_task from rest_framework.response import Response from rest_framework.views import status from rest_framework import viewsets from rest_framework.permissions import IsAuthenticated -from fyle.platform import exceptions as fyle_exc -from apps.workspaces.signals import post_delete_xero_connection -from xerosdk import exceptions as xero_exc - -from fyle_rest_auth.helpers import get_fyle_admin from fyle_rest_auth.utils import AuthUtils -from fyle_rest_auth.models import AuthToken -from apps.workspaces.tasks import schedule_sync from fyle_xero_api.utils import assert_valid -from apps.fyle.helpers import get_cluster_domain -from apps.fyle.models import ExpenseGroupSettings -from apps.xero.utils import XeroConnector -from apps.mappings.models import TenantMapping -from fyle_accounting_mappings.models import ExpenseAttribute - -from .models import Workspace, FyleCredential, XeroCredentials, WorkspaceGeneralSettings, WorkspaceSchedule, LastExportDetail -from .utils import generate_xero_identity, generate_xero_refresh_token, create_or_update_general_settings -from .serializers import WorkspaceSerializer, FyleCredentialSerializer, XeroCredentialSerializer, \ - WorkSpaceGeneralSettingsSerializer, WorkspaceScheduleSerializer, LastExportDetailSerializer +from .models import Workspace, XeroCredentials, WorkspaceGeneralSettings, LastExportDetail +from .utils import generate_xero_identity, create_or_update_general_settings +from .serializers import WorkspaceSerializer, XeroCredentialSerializer, \ + WorkSpaceGeneralSettingsSerializer, LastExportDetailSerializer from .tasks import export_to_xero from apps.exceptions import handle_view_exceptions +from .actions import connect_xero, post_workspace, revoke_connections, get_workspace_admin logger = logging.getLogger(__name__) @@ -76,36 +60,7 @@ def post(self, request): Create a Workspace """ access_token = request.META.get('HTTP_AUTHORIZATION') - fyle_user = get_fyle_admin(access_token.split(' ')[1], None) - org_name = fyle_user['data']['org']['name'] - org_id = fyle_user['data']['org']['id'] - fyle_currency = fyle_user['data']['org']['currency'] - - workspace = Workspace.objects.filter(fyle_org_id=org_id).first() - - if workspace: - workspace.user.add(User.objects.get(user_id=request.user)) - cache.delete(str(workspace.id)) - else: - workspace = Workspace.objects.create(name=org_name, fyle_currency=fyle_currency, fyle_org_id=org_id) - - ExpenseGroupSettings.objects.create(workspace_id=workspace.id) - - LastExportDetail.objects.create(workspace_id=workspace.id) - - workspace.user.add(User.objects.get(user_id=request.user)) - - auth_tokens = AuthToken.objects.get(user__user_id=request.user) - - cluster_domain = get_cluster_domain(auth_tokens.refresh_token) - - FyleCredential.objects.update_or_create( - refresh_token=auth_tokens.refresh_token, - workspace_id=workspace.id, - cluster_domain=cluster_domain - ) - - async_task('apps.workspaces.tasks.async_add_admins_to_workspace', workspace.id, request.user.user_id) + workspace = post_workspace(access_token=access_token,request=request) return Response( data=WorkspaceSerializer(workspace).data, @@ -168,49 +123,8 @@ def post(self, request, **kwargs): authorization_code = request.data.get('code') redirect_uri = request.data.get('redirect_uri') - if redirect_uri: - refresh_token = generate_xero_refresh_token(authorization_code, redirect_uri) - else: - refresh_token = generate_xero_refresh_token(authorization_code) - xero_credentials = XeroCredentials.objects.filter(workspace_id=kwargs['workspace_id']).first() - tenant_mapping = TenantMapping.objects.filter(workspace_id=kwargs['workspace_id']).first() - - workspace = Workspace.objects.get(pk=kwargs['workspace_id']) - if not xero_credentials: - xero_credentials = XeroCredentials.objects.create( - refresh_token=refresh_token, - workspace_id=kwargs['workspace_id'] - ) - - else: - xero_credentials.refresh_token = refresh_token - xero_credentials.is_expired = False - xero_credentials.save() - - if tenant_mapping and not tenant_mapping.connection_id: - xero_connector = XeroConnector(xero_credentials, workspace_id=kwargs['workspace_id']) - connections = xero_connector.connection.connections.get_all() - connection = list(filter(lambda connection: connection['tenantId'] == tenant_mapping.tenant_id, connections)) - - if connection: - tenant_mapping.connection_id = connection[0]['id'] - tenant_mapping.save() - - if tenant_mapping: - try: - xero_connector = XeroConnector(xero_credentials, workspace_id=kwargs['workspace_id']) - company_info = xero_connector.get_organisations()[0] - workspace.xero_currency = company_info['BaseCurrency'] - workspace.save() - xero_credentials.country = company_info['CountryCode'] - xero_credentials.save() - except (xero_exc.WrongParamsError, xero_exc.UnsuccessfulAuthentication) as exception: - logger.info(exception.response) - - if workspace.onboarding_state == 'CONNECTION': - workspace.onboarding_state = 'EXPORT_SETTINGS' - workspace.save() + xero_credentials = connect_xero(authorization_code=authorization_code, redirect_uri=redirect_uri, workspace_id=kwargs['workspace_id']) return Response( data=XeroCredentialSerializer(xero_credentials).data, @@ -240,26 +154,7 @@ def post(self, request, **kwargs): Post of Xero Credentials """ # TODO: cleanup later - merge with ConnectXeroView - workspace_id = kwargs['workspace_id'] - xero_credentials = XeroCredentials.objects.filter(workspace_id=workspace_id).first() - tenant_mapping = TenantMapping.objects.filter(workspace_id=workspace_id).first() - if xero_credentials: - if tenant_mapping and tenant_mapping.connection_id: - try: - xero_connector = XeroConnector(xero_credentials, workspace_id=workspace_id) - xero_connector.connection.connections.remove_connection(tenant_mapping.connection_id) - except (xero_exc.InvalidGrant, xero_exc.UnsupportedGrantType, - xero_exc.InvalidTokenError, xero_exc.UnsuccessfulAuthentication, - xero_exc.WrongParamsError, xero_exc.NoPrivilegeError, - xero_exc.InternalServerError): - pass - - xero_credentials.refresh_token = None - xero_credentials.country = None - xero_credentials.is_expired = True - xero_credentials.save() - - post_delete_xero_connection(workspace_id) + revoke_connections(workspace_id=kwargs['workspace_id']) return Response( data={ @@ -387,15 +282,7 @@ def get(self, request, *args, **kwargs): Get Admins for the workspaces """ - workspace = Workspace.objects.get(pk=kwargs['workspace_id']) - - admin_email = [] - users = workspace.user.all() - for user in users: - admin = User.objects.get(user_id=user) - employee = ExpenseAttribute.objects.filter(value=admin.email, workspace_id=kwargs['workspace_id'], attribute_type='EMPLOYEE').first() - if employee: - admin_email.append({'name': employee.detail['full_name'], 'email': admin.email}) + admin_email = get_workspace_admin(workspace_id=kwargs['workspace_id']) return Response( data=admin_email, diff --git a/apps/xero/actions.py b/apps/xero/actions.py new file mode 100644 index 00000000..2046f081 --- /dev/null +++ b/apps/xero/actions.py @@ -0,0 +1,61 @@ +from apps.workspaces.models import XeroCredentials, Workspace +from .utils import XeroConnector + +from datetime import datetime, timezone +from django_q.tasks import Chain + +from fyle_accounting_mappings.models import DestinationAttribute, MappingSetting + +def get_xero_connector(workspace_id): + xero_credentials = XeroCredentials.get_active_xero_credentials(workspace_id=workspace_id) + return XeroConnector(xero_credentials, workspace_id=workspace_id) + +def sync_tenant(workspace_id): + xero_connector = get_xero_connector(workspace_id=workspace_id) + tenants = xero_connector.sync_tenants() + return tenants + +def sync_dimensions(workspace_id): + + workspace = Workspace.objects.get(id=workspace_id) + if workspace.destination_synced_at: + time_interval = datetime.now(timezone.utc) - workspace.destination_synced_at + + if workspace.destination_synced_at is None or time_interval.days > 0: + xero_connector = get_xero_connector(workspace_id=workspace_id) + + xero_connector.sync_dimensions(workspace_id) + + workspace.destination_synced_at = datetime.now() + workspace.save(update_fields=['destination_synced_at']) + + +def refersh_xero_dimension(workspace_id): + + workspace_id = workspace_id + xero_connector = get_xero_connector(workspace_id=workspace_id) + + mapping_settings = MappingSetting.objects.filter(workspace_id=workspace_id, import_to_fyle=True) + chain = Chain() + + for mapping_setting in mapping_settings: + if mapping_setting.source_field == 'PROJECT': + # run auto_import_and_map_fyle_fields + chain.append('apps.mappings.tasks.auto_import_and_map_fyle_fields', int(workspace_id)) + elif mapping_setting.source_field == 'COST_CENTER': + # run auto_create_cost_center_mappings + chain.append('apps.mappings.tasks.auto_create_cost_center_mappings', int(workspace_id)) + elif mapping_setting.is_custom: + # run async_auto_create_custom_field_mappings + chain.append('apps.mappings.tasks.async_auto_create_custom_field_mappings', int(workspace_id)) + + if chain.length() > 0: + chain.run() + + xero_connector.sync_dimensions(workspace_id) + + workspace = Workspace.objects.get(id=workspace_id) + workspace.destination_synced_at = datetime.now() + workspace.save(update_fields=['destination_synced_at']) + + diff --git a/apps/xero/views.py b/apps/xero/views.py index 75e2e1b3..d3351c93 100644 --- a/apps/xero/views.py +++ b/apps/xero/views.py @@ -5,26 +5,16 @@ from rest_framework.response import Response from rest_framework.views import status -from fyle_accounting_mappings.models import DestinationAttribute, MappingSetting +from fyle_accounting_mappings.models import DestinationAttribute from fyle_accounting_mappings.serializers import DestinationAttributeSerializer -from xerosdk.exceptions import InvalidGrant, InvalidTokenError, UnsuccessfulAuthentication - from django_q.tasks import Chain -from apps.fyle.models import ExpenseGroup -from apps.tasks.models import TaskLog -from apps.workspaces.models import XeroCredentials, Workspace -from apps.workspaces.serializers import WorkspaceSerializer -from apps.xero.models import BankTransaction, Bill -from fyle_xero_api.utils import assert_valid - -from .utils import XeroConnector from .serializers import XeroFieldSerializer -from .tasks import create_bank_transaction, schedule_bank_transaction_creation, create_bill, schedule_bills_creation, \ - create_payment, check_xero_object_status, process_reimbursements, create_chain_and_export from apps.exceptions import handle_view_exceptions +from .actions import get_xero_connector, sync_tenant, sync_dimensions, refersh_xero_dimension + class TokenHealthView(generics.RetrieveAPIView): """ Token Health View @@ -32,8 +22,8 @@ class TokenHealthView(generics.RetrieveAPIView): @handle_view_exceptions() def get(self, request, *args, **kwargs): - xero_credentials = XeroCredentials.get_active_xero_credentials(workspace_id=kwargs['workspace_id']) - XeroConnector(xero_credentials, workspace_id=kwargs['workspace_id']) + + get_xero_connector(workspace_id = self.kwargs['workspace_id']) return Response( status=status.HTTP_200_OK @@ -56,12 +46,8 @@ def post(self, request, *args, **kwargs): """ Get tenants from Xero """ - - xero_credentials = XeroCredentials.get_active_xero_credentials(workspace_id=kwargs['workspace_id']) - xero_connector = XeroConnector(xero_credentials, workspace_id=kwargs['workspace_id']) - - tenants = xero_connector.sync_tenants() + tenants = sync_tenant(workspace_id=self.kwargs['workspace_id']) return Response( data=self.serializer_class(tenants, many=True).data, @@ -94,19 +80,8 @@ def post(self, request, *args, **kwargs): Sync Data From Xero """ - workspace = Workspace.objects.get(id=kwargs['workspace_id']) - if workspace.destination_synced_at: - time_interval = datetime.now(timezone.utc) - workspace.destination_synced_at - - if workspace.destination_synced_at is None or time_interval.days > 0: - xero_credentials = XeroCredentials.get_active_xero_credentials(workspace_id=kwargs['workspace_id']) - xero_connector = XeroConnector(xero_credentials, workspace_id=kwargs['workspace_id']) - - xero_connector.sync_dimensions(kwargs['workspace_id']) - - workspace.destination_synced_at = datetime.now() - workspace.save(update_fields=['destination_synced_at']) - + sync_dimensions(workspace_id=self.kwargs['workspace_id']) + return Response( status=status.HTTP_200_OK ) @@ -123,32 +98,7 @@ def post(self, request, *args, **kwargs): Sync data from Xero """ - workspace_id = kwargs['workspace_id'] - xero_credentials = XeroCredentials.get_active_xero_credentials(workspace_id=workspace_id) - xero_connector = XeroConnector(xero_credentials, workspace_id=workspace_id) - - mapping_settings = MappingSetting.objects.filter(workspace_id=workspace_id, import_to_fyle=True) - chain = Chain() - - for mapping_setting in mapping_settings: - if mapping_setting.source_field == 'PROJECT': - # run auto_import_and_map_fyle_fields - chain.append('apps.mappings.tasks.auto_import_and_map_fyle_fields', int(workspace_id)) - elif mapping_setting.source_field == 'COST_CENTER': - # run auto_create_cost_center_mappings - chain.append('apps.mappings.tasks.auto_create_cost_center_mappings', int(workspace_id)) - elif mapping_setting.is_custom: - # run async_auto_create_custom_field_mappings - chain.append('apps.mappings.tasks.async_auto_create_custom_field_mappings', int(workspace_id)) - - if chain.length() > 0: - chain.run() - - xero_connector.sync_dimensions(workspace_id) - - workspace = Workspace.objects.get(id=workspace_id) - workspace.destination_synced_at = datetime.now() - workspace.save(update_fields=['destination_synced_at']) + refersh_xero_dimension(workspace_id=self.kwargs['workspace_id']) return Response( status=status.HTTP_200_OK diff --git a/tests/test_workspaces/test_views.py b/tests/test_workspaces/test_views.py index 13f7d778..7cb06598 100644 --- a/tests/test_workspaces/test_views.py +++ b/tests/test_workspaces/test_views.py @@ -72,12 +72,12 @@ def test_post_of_workspace(api_client, test_connection, mocker): api_client.credentials(HTTP_AUTHORIZATION='Bearer {}'.format(test_connection.access_token)) mocker.patch( - 'apps.workspaces.views.get_fyle_admin', + 'apps.workspaces.actions.get_fyle_admin', return_value=fyle_data['get_my_profile'] ) mocker.patch( - 'apps.workspaces.views.get_cluster_domain', + 'apps.workspaces.actions.get_cluster_domain', return_value={ 'cluster_domain': 'https://staging.fyle.tech/' } @@ -89,7 +89,7 @@ def test_post_of_workspace(api_client, test_connection, mocker): assert dict_compare_keys(response, data['workspace']) == [], 'workspaces api returns a diff in the keys' mocker.patch( - 'apps.workspaces.views.get_fyle_admin', + 'apps.workspaces.actions.get_fyle_admin', return_value=fyle_data['get_exsisting_org'] ) @@ -113,7 +113,7 @@ def test_connect_xero_view_post(mocker, api_client, test_connection): tenant_mapping = TenantMapping.objects.filter(workspace_id=workspace_id).first() mocker.patch( - 'apps.workspaces.views.generate_xero_refresh_token', + 'apps.workspaces.actions.generate_xero_refresh_token', return_value='asdfghjk' ) @@ -163,7 +163,7 @@ def test_connect_xero_view_exceptions(api_client, test_connection): api_client.credentials(HTTP_AUTHORIZATION='Bearer {}'.format(test_connection.access_token)) - with mock.patch('apps.workspaces.views.generate_xero_refresh_token') as mock_call: + with mock.patch('apps.workspaces.actions.generate_xero_refresh_token') as mock_call: mock_call.side_effect = xero_exc.InvalidClientError(msg='Invalid client', response=json.dumps({'message': 'Invalid client'})) response = api_client.post(