diff --git a/apps/quickbooks_online/exceptions.py b/apps/quickbooks_online/exceptions.py index c38b08a8..22806254 100644 --- a/apps/quickbooks_online/exceptions.py +++ b/apps/quickbooks_online/exceptions.py @@ -88,6 +88,14 @@ def new_fn(*args): detail = {'expense_group_id': expense_group.id, 'message': 'QBO Account not connected / token expired'} task_log.status = 'FAILED' task_log.detail = detail + qbo_credentials = QBOCredential.objects.filter( + workspace_id=expense_group.workspace_id + ).first() + + if qbo_credentials: + qbo_credentials.is_expired = True + qbo_credentials.refresh_token = None + qbo_credentials.save() task_log.save() diff --git a/apps/workspaces/actions.py b/apps/workspaces/actions.py index 1978954c..03cdcde1 100644 --- a/apps/workspaces/actions.py +++ b/apps/workspaces/actions.py @@ -248,6 +248,15 @@ def post_to_integration_settings(workspace_id: int, active: bool): def export_to_qbo(workspace_id, export_mode=None, expense_group_ids=[]): + active_qbo_credentials = QBOCredential.objects.filter( + workspace_id=workspace_id, + is_expired=False, + refresh_token__isnull=False + ).first() + + if not active_qbo_credentials: + return + general_settings = WorkspaceGeneralSettings.objects.get(workspace_id=workspace_id) last_export_detail = LastExportDetail.objects.get(workspace_id=workspace_id) workspace_schedule = WorkspaceSchedule.objects.filter(workspace_id=workspace_id, interval_hours__gt=0, enabled=True).first() diff --git a/tests/test_quickbooks_online/test_tasks.py b/tests/test_quickbooks_online/test_tasks.py index 1043fd5b..e47e3c25 100644 --- a/tests/test_quickbooks_online/test_tasks.py +++ b/tests/test_quickbooks_online/test_tasks.py @@ -173,6 +173,7 @@ def test_create_bill_exceptions(db, create_task_logs): expense.save() expense_group.expenses.set(expenses) + qbo_credentials = QBOCredential.objects.filter(workspace_id=expense_group.workspace_id).first() with mock.patch('apps.quickbooks_online.models.Bill.create_bill') as mock_call: mock_call.side_effect = QBOCredential.DoesNotExist() @@ -181,18 +182,24 @@ def test_create_bill_exceptions(db, create_task_logs): task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = BulkError(msg='employess not found', response='mapping error') create_bill(expense_group, task_log.id, True) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = Exception() create_bill(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FATAL' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = WrongParamsError(msg={'Message': 'Invalid parametrs'}, response=json.dumps({'Fault': {'Error': [{'code': 400, 'Message': 'Invalid parametrs', 'Detail': 'Invalid parametrs'}], 'type': 'Invalid_params'}})) create_bill(expense_group, task_log.id, False) @@ -383,6 +390,7 @@ def test_post_qbo_expenses_exceptions(create_task_logs, db): qbo_expense_lineitem = QBOExpenseLineitem.objects.get(expense_id=7) qbo_expense_lineitem.expense_id = 24 qbo_expense_lineitem.save() + qbo_credentials = QBOCredential.objects.filter(workspace_id=expense_group.workspace_id).first() with mock.patch('apps.quickbooks_online.models.QBOExpense.create_qbo_expense') as mock_call: mock_call.side_effect = QBOCredential.DoesNotExist() @@ -391,18 +399,24 @@ def test_post_qbo_expenses_exceptions(create_task_logs, db): task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = BulkError(msg='employess not found', response='mapping error') create_qbo_expense(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = Exception() create_qbo_expense(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FATAL' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = WrongParamsError(msg={'Message': 'Invalid parametrs'}, response=json.dumps({'Fault': {'Error': [{'code': 400, 'Message': 'Invalid parametrs', 'Detail': 'Invalid parametrs'}], 'type': 'Invalid_params'}})) create_qbo_expense(expense_group, task_log.id, False) @@ -464,6 +478,7 @@ def test_post_credit_card_exceptions(mocker, create_task_logs, db): expense.save() expense_group.expenses.set(expenses) + qbo_credentials = QBOCredential.objects.filter(workspace_id=expense_group.workspace_id).first() with mock.patch('apps.quickbooks_online.models.CreditCardPurchase.create_credit_card_purchase') as mock_call: mock_call.side_effect = QBOCredential.DoesNotExist() @@ -472,18 +487,24 @@ def test_post_credit_card_exceptions(mocker, create_task_logs, db): task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = BulkError(msg='employess not found', response='mapping error') create_credit_card_purchase(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = Exception() create_credit_card_purchase(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FATAL' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = WrongParamsError(msg={'Message': 'Invalid parametrs'}, response=json.dumps({'Fault': {'Error': [{'code': 400, 'Message': 'Invalid parametrs', 'Detail': 'Invalid parametrs'}], 'type': 'Invalid_params'}})) create_credit_card_purchase(expense_group, task_log.id, False) @@ -567,6 +588,8 @@ def test_post_create_journal_entry_exceptions(create_task_logs, db): expense_group.expenses.set(expenses) expense_group.save() + qbo_credentials = QBOCredential.objects.filter(workspace_id=expense_group.workspace_id).first() + with mock.patch('apps.quickbooks_online.models.JournalEntry.create_journal_entry') as mock_call: mock_call.side_effect = QBOCredential.DoesNotExist() create_journal_entry(expense_group, task_log.id, False) @@ -574,18 +597,24 @@ def test_post_create_journal_entry_exceptions(create_task_logs, db): task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = BulkError(msg='employess not found', response='mapping error') create_journal_entry(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = Exception() create_journal_entry(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FATAL' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = WrongParamsError(msg={'Message': 'Invalid parametrs'}, response=json.dumps({'Fault': {'Error': [{'code': 400, 'Message': 'Invalid parametrs', 'Detail': 'Invalid parametrs'}], 'type': 'Invalid_params'}})) create_journal_entry(expense_group, task_log.id, False) @@ -636,6 +665,8 @@ def test_post_create_cheque_exceptions(create_task_logs, db): expense_group.expenses.set(expenses) expense_group.save() + qbo_credentials = QBOCredential.objects.filter(workspace_id=expense_group.workspace_id).first() + with mock.patch('apps.quickbooks_online.models.Cheque.create_cheque') as mock_call: mock_call.side_effect = QBOCredential.DoesNotExist() create_cheque(expense_group, task_log.id, False) @@ -643,18 +674,24 @@ def test_post_create_cheque_exceptions(create_task_logs, db): task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = BulkError(msg='employess not found', response='mapping error') create_cheque(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FAILED' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = Exception() create_cheque(expense_group, task_log.id, False) task_log = TaskLog.objects.get(id=task_log.id) assert task_log.status == 'FATAL' + qbo_credentials.is_expired = False + qbo_credentials.save() mock_call.side_effect = WrongParamsError(msg={'Message': 'Invalid parametrs'}, response=json.dumps({'Fault': {'Error': [{'code': 400, 'Message': 'Invalid parametrs', 'Detail': 'Invalid parametrs'}], 'type': 'Invalid_params'}})) create_cheque(expense_group, task_log.id, False) diff --git a/tests/test_workspaces/test_views.py b/tests/test_workspaces/test_views.py index 5ffb7ba4..f30cab3a 100644 --- a/tests/test_workspaces/test_views.py +++ b/tests/test_workspaces/test_views.py @@ -1,13 +1,16 @@ import json from unittest import mock +from datetime import datetime, timedelta from django.urls import reverse from qbosdk import exceptions as qbo_exc -from apps.workspaces.models import QBOCredential, Workspace, WorkspaceGeneralSettings +from apps.workspaces.models import QBOCredential, Workspace, WorkspaceGeneralSettings, LastExportDetail from fyle_qbo_api.tests import settings from tests.helper import dict_compare_keys from tests.test_workspaces.fixtures import data +from apps.workspaces.actions import export_to_qbo +from apps.fyle.models import ExpenseGroup def test_get_workspace(api_client, test_connection): @@ -201,6 +204,24 @@ def test_export_to_qbo(mocker, api_client, test_connection): response = api_client.post(url) assert response.status_code == 200 + ExpenseGroup.objects.filter(workspace_id=workspace_id).update(exported_at=None) + expense_group_ids = ExpenseGroup.objects.filter(workspace_id=workspace_id).values_list('id', flat=True) + + qbo_credentials = QBOCredential.get_active_qbo_credentials(workspace_id) + assert qbo_credentials is not None + assert len(expense_group_ids) != 0 + export_to_qbo(workspace_id, expense_group_ids=expense_group_ids) + last_export_detail = LastExportDetail.objects.get(workspace_id=workspace_id) + last_exported_at = last_export_detail.last_exported_at + assert last_exported_at.replace(tzinfo=None) > (datetime.now() - timedelta(minutes=1)).replace(tzinfo=None) + + qbo_credentials.is_expired = True + qbo_credentials.save() + + export_to_qbo(workspace_id, expense_group_ids=expense_group_ids) + last_export_detail = LastExportDetail.objects.get(workspace_id=workspace_id) + assert last_export_detail.last_exported_at == last_exported_at + def test_last_export_detail_view(db, api_client, test_connection): workspace_id = 3