Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for skip expense post import of expenses #712

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 3 additions & 2 deletions apps/fyle/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def update_expenses_in_progress(in_progress_expenses: List[Expense]) -> None:
__bulk_update_expenses(expense_to_be_updated)


def mark_expenses_as_skipped(final_query: Q, expenses_object_ids: List, workspace: Workspace) -> None:
def mark_expenses_as_skipped(final_query: Q, expenses_object_ids: List, workspace: Workspace) -> List[Expense]:
"""
Mark expenses as skipped in bulk
:param final_query: final query
Expand All @@ -137,7 +137,6 @@ def mark_expenses_as_skipped(final_query: Q, expenses_object_ids: List, workspac
expenses_to_be_skipped = Expense.objects.filter(
final_query,
id__in=expenses_object_ids,
expensegroup__isnull=True,
org_id=workspace.fyle_org_id
)

Expand All @@ -158,6 +157,8 @@ def mark_expenses_as_skipped(final_query: Q, expenses_object_ids: List, workspac

__bulk_update_expenses(expense_to_be_updated)

return expenses_to_be_skipped


def mark_accounting_export_summary_as_synced(expenses: List[Expense]) -> None:
"""
Expand Down
39 changes: 38 additions & 1 deletion apps/fyle/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
)
from apps.fyle.models import Expense, ExpenseFilter, ExpenseGroup, ExpenseGroupSettings
from apps.fyle.queue import async_post_accounting_export_summary
from apps.tasks.models import TaskLog
from apps.tasks.models import TaskLog, Error
from apps.workspaces.actions import export_to_qbo
from apps.workspaces.models import FyleCredential, Workspace, WorkspaceGeneralSettings
from fyle_qbo_api.logging_middleware import get_logger
Expand Down Expand Up @@ -317,3 +317,40 @@ def update_non_exported_expenses(data: Dict) -> None:
Expense.create_expense_objects(
expense_objects, expense.workspace_id, skip_update=True
)


def skip_expenses_pre_export(workspace_id: int, expense_group_ids: List[int]) -> None:
"""
Skip expenses before export
:param workspace_id: Workspace id
:param expense_group_ids: Expense group ids
:return: None
"""
expense_filters = ExpenseFilter.objects.filter(workspace_id=workspace_id).order_by('rank')
if expense_filters:
workspace = Workspace.objects.get(pk=workspace_id)
expense_ids_queued = Expense.objects.filter(expensegroup__id__in=expense_group_ids).values_list('id', flat=True)
filtered_expense_query = construct_expense_filter_query(expense_filters)
skipped_expenses = mark_expenses_as_skipped(filtered_expense_query, expense_ids_queued, workspace)

if skipped_expenses:
skipped_expense_ids = [expense.id for expense in skipped_expenses]
logger.info('Skipping expenses before export %s', skipped_expense_ids)

expense_groups = ExpenseGroup.objects.filter(expenses__id__in=skipped_expense_ids)

for expense_group in expense_groups:
task_log = TaskLog.objects.filter(workspace_id=workspace_id, expense_group_id=expense_group.id).first()
if task_log:
logger.info('Deleting task log for expense group %s before export', expense_group.id)
task_log.delete()

error = Error.objects.filter(workspace_id=workspace_id, expense_group_id=expense_group.id).first()
if error:
logger.info('Deleting error for expense group %s before export', expense_group.id)
error.delete()

expense_group.expenses.remove(*skipped_expenses)
if not expense_group.expenses.exists():
logger.info('Deleting empty expense group %s before export', expense_group.id)
expense_group.delete()
7 changes: 6 additions & 1 deletion apps/quickbooks_online/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django_q.models import Schedule
from django_q.tasks import Chain, async_task

from apps.fyle.models import Expense, ExpenseGroup
from apps.fyle.models import Expense, ExpenseGroup, ExpenseFilter
from apps.tasks.models import TaskLog, Error
from apps.workspaces.models import FyleCredential, WorkspaceGeneralSettings

Expand Down Expand Up @@ -92,6 +92,11 @@ def __create_chain_and_run(fyle_credentials: FyleCredential, in_progress_expense
"""
chain = Chain()

expense_filters = ExpenseFilter.objects.filter(workspace_id=workspace_id)
if expense_filters.count():
expense_group_ids = [task['expense_group'].id for task in chain_tasks]
chain.append('apps.fyle.tasks.skip_expenses_pre_export', workspace_id, expense_group_ids)

chain.append('apps.quickbooks_online.tasks.update_expense_and_post_summary', in_progress_expenses, workspace_id, fund_source)
chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials, True)

Expand Down
33 changes: 31 additions & 2 deletions tests/test_fyle/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
from rest_framework.exceptions import ValidationError
from rest_framework import status

from apps.fyle.models import Expense, ExpenseGroup, ExpenseGroupSettings
from apps.fyle.models import Expense, ExpenseGroup, ExpenseGroupSettings, ExpenseFilter
anishfyle marked this conversation as resolved.
Show resolved Hide resolved
from apps.fyle.tasks import (
create_expense_groups,
post_accounting_export_summary,
import_and_export_expenses,
sync_dimensions,
update_non_exported_expenses
update_non_exported_expenses,
skip_expenses_pre_export
)
from apps.fyle.actions import mark_expenses_as_skipped
from apps.tasks.models import TaskLog
Expand Down Expand Up @@ -208,3 +209,31 @@ def test_update_non_exported_expenses(db, create_temp_workspace, mocker, api_cli
url = reverse('exports', kwargs={'workspace_id': 2})
response = api_client.post(url, data=payload, format='json')
assert response.status_code == status.HTTP_400_BAD_REQUEST


def test_skip_expenses_pre_export(db):
ExpenseFilter.objects.create(
workspace_id=1,
condition='employee_email',
operator='in',
values=['[email protected]', '[email protected]'],
rank=1,
join_by='OR',
)
ExpenseFilter.objects.create(
workspace_id=1,
condition='claim_number',
operator='in',
values=['ajdnwjnadw', 'ajdnwjnlol'],
rank=2,
)

expenses = list(data["expenses_spent_at"])
for expense in expenses:
expense['org_id'] = 'orHVw3ikkCxJ'

expense_objects = Expense.create_expense_objects(expenses, 1)
ExpenseGroup.create_expense_groups_by_report_id_fund_source(expense_objects, 1)

expense_group_ids = ExpenseGroup.objects.filter(workspace_id=1).values_list('id', flat=True)
skip_expenses_pre_export(1, expense_group_ids)
anishfyle marked this conversation as resolved.
Show resolved Hide resolved
Loading