From 6e513e5c643d9ed6f15b6839dbfa55f561849446 Mon Sep 17 00:00:00 2001 From: ruuushhh Date: Mon, 26 Jun 2023 11:50:30 +0530 Subject: [PATCH 1/5] Refactoring completed --- apps/mappings/signals.py | 4 +- apps/mappings/tasks.py | 113 ----- apps/mappings/utils.py | 4 +- apps/quickbooks_online/tasks.py | 270 ----------- .../apis/advanced_configurations/triggers.py | 5 +- .../apis/import_settings/triggers.py | 3 +- .../workspaces/apis/map_employees/triggers.py | 2 +- apps/workspaces/tasks.py | 26 +- apps/workspaces/utils.py | 7 +- fyle_qbo_api/queue.py | 419 ++++++++++++++++++ tests/test_mappings/test_tasks.py | 1 + tests/test_quickbooks_online/test_tasks.py | 1 + 12 files changed, 435 insertions(+), 420 deletions(-) create mode 100644 fyle_qbo_api/queue.py diff --git a/apps/mappings/signals.py b/apps/mappings/signals.py index dd128ddd..6a7294a5 100644 --- a/apps/mappings/signals.py +++ b/apps/mappings/signals.py @@ -8,8 +8,8 @@ from fyle_accounting_mappings.models import MappingSetting, Mapping, EmployeeMapping from apps.tasks.models import Error -from apps.mappings.tasks import upload_attributes_to_fyle, schedule_cost_centers_creation,\ - schedule_fyle_attributes_creation +from fyle_qbo_api.queue import schedule_cost_centers_creation, schedule_fyle_attributes_creation +from apps.mappings.tasks import upload_attributes_to_fyle from apps.workspaces.utils import delete_cards_mapping_settings from apps.workspaces.models import WorkspaceGeneralSettings diff --git a/apps/mappings/tasks.py b/apps/mappings/tasks.py index a92a089c..6ad8cdb1 100644 --- a/apps/mappings/tasks.py +++ b/apps/mappings/tasks.py @@ -275,27 +275,6 @@ def auto_create_project_mappings(workspace_id: int): post_projects_in_batches(platform, workspace_id, mapping_setting.destination_field) -def schedule_tax_groups_creation(import_tax_codes, workspace_id): - if import_tax_codes: - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.auto_create_tax_codes_mappings', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': datetime.now() - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.auto_create_tax_codes_mappings', - args='{}'.format(workspace_id), - ).first() - - if schedule: - schedule.delete() - - def create_fyle_categories_payload(categories: List[DestinationAttribute], workspace_id: int, updated_categories: List[ExpenseAttribute] = None): """ @@ -620,28 +599,6 @@ def async_auto_map_employees(workspace_id: int): destination_attribute_type=destination_type ) -def schedule_auto_map_employees(employee_mapping_preference: str, workspace_id: int): - if employee_mapping_preference: - start_datetime = datetime.now() - - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.async_auto_map_employees', - args='{0}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.async_auto_map_employees', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - def auto_map_ccc_employees(default_ccc_account_id: str, workspace_id: int): """ @@ -706,31 +663,6 @@ def async_auto_map_ccc_account(workspace_id: int): auto_map_ccc_employees(default_ccc_account_id, workspace_id) -def schedule_auto_map_ccc_employees(workspace_id: int): - general_settings = WorkspaceGeneralSettings.objects.get(workspace_id=workspace_id) - - if general_settings.auto_map_employees and general_settings.corporate_credit_card_expenses_object != 'BILL': - start_datetime = datetime.now() - - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.async_auto_map_ccc_account', - args='{0}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.async_auto_map_ccc_account', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - def upload_tax_groups_to_fyle(platform_connection: PlatformConnector, workspace_id: int): existing_tax_codes_name = ExpenseAttribute.objects.filter( attribute_type='TAX_GROUP', workspace_id=workspace_id).values_list('value', flat=True) @@ -859,27 +791,6 @@ def auto_create_cost_center_mappings(workspace_id): post_cost_centers_in_batches(platform, workspace_id, mapping_setting.destination_field) -def schedule_cost_centers_creation(import_to_fyle, workspace_id): - if import_to_fyle: - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.auto_create_cost_center_mappings', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': datetime.now() - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.auto_create_cost_center_mappings', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - def create_fyle_expense_custom_field_payload( qbo_attributes: List[DestinationAttribute], workspace_id: int, fyle_attribute: str, platform: PlatformConnector, source_placeholder: str = None @@ -1013,30 +924,6 @@ def async_auto_create_custom_field_mappings(workspace_id): ) -def schedule_fyle_attributes_creation(workspace_id: int): - mapping_settings = MappingSetting.objects.filter( - is_custom=True, import_to_fyle=True, workspace_id=workspace_id - ).all() - if mapping_settings: - schedule, _ = Schedule.objects.get_or_create( - func='apps.mappings.tasks.async_auto_create_custom_field_mappings', - args='{0}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': datetime.now() + timedelta(hours=24) - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.async_auto_create_custom_field_mappings', - args='{0}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - def create_fyle_merchants_payload(vendors, existing_merchants_name): payload: List[str] = [] for vendor in vendors: diff --git a/apps/mappings/utils.py b/apps/mappings/utils.py index 30122f8f..052e4272 100644 --- a/apps/mappings/utils.py +++ b/apps/mappings/utils.py @@ -2,12 +2,10 @@ from django.db.models import Q -from apps.quickbooks_online.tasks import schedule_bill_payment_creation +from fyle_qbo_api.queue import schedule_bill_payment_creation, schedule_auto_map_ccc_employees from apps.workspaces.models import WorkspaceGeneralSettings from fyle_qbo_api.utils import assert_valid -from .tasks import schedule_auto_map_ccc_employees - from .models import GeneralMapping diff --git a/apps/quickbooks_online/tasks.py b/apps/quickbooks_online/tasks.py index 3ca91aa9..d78fa5a6 100644 --- a/apps/quickbooks_online/tasks.py +++ b/apps/quickbooks_online/tasks.py @@ -232,48 +232,6 @@ def create_or_update_employee_mapping(expense_group: ExpenseGroup, qbo_connectio }]) -def schedule_bills_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule bills creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, bill__id__isnull=True, exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_BILL' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_BILL' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_bill', expense_group, task_log.id, last_export) - - if chain.length() > 1: - chain.run() - - @handle_qbo_exceptions() def create_bill(expense_group, task_log_id, last_export: bool): task_log = TaskLog.objects.get(id=task_log_id) @@ -567,46 +525,7 @@ def __validate_expense_group(expense_group: ExpenseGroup, general_settings: Work raise BulkError('Mappings are missing', bulk_errors) -def schedule_cheques_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule cheque creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, cheque__id__isnull=True, exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_CHECK' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_CHECK' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_cheque', expense_group, task_log.id, last_export) - if chain.length() > 1: - chain.run() @handle_qbo_exceptions() def create_cheque(expense_group, task_log_id, last_export: bool): @@ -653,46 +572,7 @@ def create_cheque(expense_group, task_log_id, last_export: bool): if last_export: update_last_export_details(expense_group.workspace_id) -def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule QBO expense creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, qboexpense__id__isnull=True, exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else 'CREATING_DEBIT_CARD_EXPENSE' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else 'CREATING_DEBIT_CARD_EXPENSE' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_qbo_expense', expense_group, task_log.id, last_export) - - if chain.length() > 1: - chain.run() @handle_qbo_exceptions() @@ -747,48 +627,6 @@ def create_qbo_expense(expense_group, task_log_id, last_export: bool): if last_export: update_last_export_details(expense_group.workspace_id) -def schedule_credit_card_purchase_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule credit card purchase creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, creditcardpurchase__id__isnull=True, - exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_CREDIT_CARD_PURCHASE' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_CREDIT_CARD_PURCHASE' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_credit_card_purchase', expense_group, task_log.id, last_export) - - if chain.length() > 1: - chain.run() - @handle_qbo_exceptions() def create_credit_card_purchase(expense_group: ExpenseGroup, task_log_id, last_export: bool): @@ -845,47 +683,6 @@ def create_credit_card_purchase(expense_group: ExpenseGroup, task_log_id, last_e if last_export: update_last_export_details(expense_group.workspace_id) -def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule journal_entry creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, journalentry__id__isnull=True, exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_JOURNAL_ENTRY' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_JOURNAL_ENTRY' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_journal_entry', expense_group, task_log.id, last_export) - - if chain.length() > 1: - chain.run() - @handle_qbo_exceptions() def create_journal_entry(expense_group, task_log_id, last_export: bool): @@ -1006,29 +803,6 @@ def create_bill_payment(workspace_id): ) process_bill_payments(bill, workspace_id, task_log) -def schedule_bill_payment_creation(sync_fyle_to_qbo_payments, workspace_id): - general_mappings: GeneralMapping = GeneralMapping.objects.filter(workspace_id=workspace_id).first() - if general_mappings: - if sync_fyle_to_qbo_payments and general_mappings.bill_payment_account_id: - start_datetime = datetime.now() - schedule, _ = Schedule.objects.update_or_create( - func='apps.quickbooks_online.tasks.create_bill_payment', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - if not sync_fyle_to_qbo_payments: - schedule: Schedule = Schedule.objects.filter( - func='apps.quickbooks_online.tasks.create_bill_payment', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - def get_all_qbo_object_ids(qbo_objects): qbo_objects_details = {} @@ -1076,28 +850,6 @@ def check_qbo_object_status(workspace_id): logger.info('QBO token expired workspace_id - %s %s', workspace_id, {'error': exception.response}) -def schedule_qbo_objects_status_sync(sync_qbo_to_fyle_payments, workspace_id): - if sync_qbo_to_fyle_payments: - start_datetime = datetime.now() - schedule, _ = Schedule.objects.update_or_create( - func='apps.quickbooks_online.tasks.check_qbo_object_status', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.quickbooks_online.tasks.check_qbo_object_status', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - def process_reimbursements(workspace_id): fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) @@ -1129,28 +881,6 @@ def process_reimbursements(workspace_id): platform.reimbursements.sync() -def schedule_reimbursements_sync(sync_qbo_to_fyle_payments, workspace_id): - if sync_qbo_to_fyle_payments: - start_datetime = datetime.now() + timedelta(hours=12) - schedule, _ = Schedule.objects.update_or_create( - func='apps.quickbooks_online.tasks.process_reimbursements', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.quickbooks_online.tasks.process_reimbursements', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - def async_sync_accounts(workspace_id): try: qbo_credentials: QBOCredential = QBOCredential.get_active_qbo_credentials(workspace_id) diff --git a/apps/workspaces/apis/advanced_configurations/triggers.py b/apps/workspaces/apis/advanced_configurations/triggers.py index a361beb6..d381323b 100644 --- a/apps/workspaces/apis/advanced_configurations/triggers.py +++ b/apps/workspaces/apis/advanced_configurations/triggers.py @@ -1,6 +1,7 @@ from apps.workspaces.models import WorkspaceGeneralSettings -from apps.quickbooks_online.tasks import schedule_bill_payment_creation, schedule_qbo_objects_status_sync, \ - schedule_reimbursements_sync +from fyle_qbo_api.queue import (schedule_bill_payment_creation, schedule_qbo_objects_status_sync, + schedule_reimbursements_sync) + class AdvancedConfigurationsTriggers: diff --git a/apps/workspaces/apis/import_settings/triggers.py b/apps/workspaces/apis/import_settings/triggers.py index 78fb8903..7c42596b 100644 --- a/apps/workspaces/apis/import_settings/triggers.py +++ b/apps/workspaces/apis/import_settings/triggers.py @@ -9,8 +9,7 @@ from apps.fyle.models import ExpenseGroupSettings from apps.mappings.helpers import schedule_or_delete_fyle_import_tasks from apps.workspaces.models import WorkspaceGeneralSettings - -from apps.mappings.tasks import schedule_cost_centers_creation, schedule_fyle_attributes_creation, schedule_tax_groups_creation +from fyle_qbo_api.queue import schedule_cost_centers_creation, schedule_fyle_attributes_creation, schedule_tax_groups_creation class ImportSettingsTrigger: diff --git a/apps/workspaces/apis/map_employees/triggers.py b/apps/workspaces/apis/map_employees/triggers.py index 58824f5b..c16d4233 100644 --- a/apps/workspaces/apis/map_employees/triggers.py +++ b/apps/workspaces/apis/map_employees/triggers.py @@ -1,4 +1,4 @@ -from apps.mappings.tasks import schedule_auto_map_employees +from fyle_qbo_api.queue import schedule_auto_map_employees from apps.workspaces.models import WorkspaceGeneralSettings diff --git a/apps/workspaces/tasks.py b/apps/workspaces/tasks.py index 2b15cc86..7b56dff6 100644 --- a/apps/workspaces/tasks.py +++ b/apps/workspaces/tasks.py @@ -10,12 +10,12 @@ from django_q.models import Schedule from django.utils.safestring import mark_safe +from fyle_qbo_api.queue import (schedule_email_notification, schedule_bills_creation, schedule_cheques_creation, + schedule_journal_entry_creation, schedule_credit_card_purchase_creation, schedule_qbo_expense_creation) from apps.workspaces.models import User, Workspace, WorkspaceSchedule, WorkspaceGeneralSettings, LastExportDetail, QBOCredential, FyleCredential from apps.fyle.tasks import async_create_expense_groups from apps.fyle.models import Expense, ExpenseGroup -from apps.fyle.serializers import ExpenseSerializer, ExpenseGroupSerializer -from apps.quickbooks_online.tasks import schedule_bills_creation, schedule_cheques_creation, \ - schedule_journal_entry_creation, schedule_credit_card_purchase_creation, schedule_qbo_expense_creation + from apps.tasks.models import TaskLog from fyle_accounting_mappings.models import ExpenseAttribute from apps.tasks.models import Error @@ -23,26 +23,6 @@ logger = logging.getLogger(__name__) logger.level = logging.INFO -def schedule_email_notification(workspace_id: int, schedule_enabled: bool, hours: int): - if schedule_enabled: - schedule, _ = Schedule.objects.update_or_create( - func='apps.workspaces.tasks.run_email_notification', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': hours * 60, - 'next_run': datetime.now() + timedelta(minutes=10) - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.workspaces.tasks.run_email_notification', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - def schedule_sync(workspace_id: int, schedule_enabled: bool, hours: int, email_added: List, emails_selected: List): ws_schedule, _ = WorkspaceSchedule.objects.get_or_create( diff --git a/apps/workspaces/utils.py b/apps/workspaces/utils.py index 37c830c4..29ade528 100644 --- a/apps/workspaces/utils.py +++ b/apps/workspaces/utils.py @@ -11,10 +11,9 @@ from qbosdk import UnauthorizedClientError, NotFoundClientError, WrongParamsError, InternalServerError from fyle_accounting_mappings.models import MappingSetting -from apps.mappings.tasks import schedule_auto_map_employees, schedule_auto_map_ccc_employees, \ - schedule_tax_groups_creation -from apps.quickbooks_online.tasks import schedule_bill_payment_creation, schedule_qbo_objects_status_sync,\ - schedule_reimbursements_sync +from fyle_qbo_api.queue import (schedule_tax_groups_creation, schedule_auto_map_employees, + schedule_auto_map_ccc_employees, schedule_bill_payment_creation, + schedule_qbo_objects_status_sync, schedule_reimbursements_sync) from fyle_qbo_api.utils import assert_valid from .models import WorkspaceGeneralSettings, LastExportDetail diff --git a/fyle_qbo_api/queue.py b/fyle_qbo_api/queue.py new file mode 100644 index 00000000..ed5545f7 --- /dev/null +++ b/fyle_qbo_api/queue.py @@ -0,0 +1,419 @@ +from datetime import datetime, timedelta +from django_q.models import Schedule +from django_q.tasks import Chain +from typing import List +from django.db.models import Q +from apps.tasks.models import Error, TaskLog +from apps.mappings.models import GeneralMapping +from apps.workspaces.models import WorkspaceGeneralSettings, FyleCredential +from fyle_accounting_mappings.models import MappingSetting + +from apps.fyle.models import Expense, ExpenseGroup + + +def schedule_cost_centers_creation(import_to_fyle, workspace_id): + if import_to_fyle: + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.auto_create_cost_center_mappings', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': datetime.now() + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.auto_create_cost_center_mappings', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_fyle_attributes_creation(workspace_id: int): + mapping_settings = MappingSetting.objects.filter( + is_custom=True, import_to_fyle=True, workspace_id=workspace_id + ).all() + if mapping_settings: + schedule, _ = Schedule.objects.get_or_create( + func='apps.mappings.tasks.async_auto_create_custom_field_mappings', + args='{0}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': datetime.now() + timedelta(hours=24) + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.async_auto_create_custom_field_mappings', + args='{0}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_tax_groups_creation(import_tax_codes, workspace_id): + if import_tax_codes: + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.auto_create_tax_codes_mappings', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': datetime.now() + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.auto_create_tax_codes_mappings', + args='{}'.format(workspace_id), + ).first() + + if schedule: + schedule.delete() + + +def schedule_auto_map_employees(employee_mapping_preference: str, workspace_id: int): + if employee_mapping_preference: + start_datetime = datetime.now() + + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.async_auto_map_employees', + args='{0}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.async_auto_map_employees', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_auto_map_ccc_employees(workspace_id: int): + general_settings = WorkspaceGeneralSettings.objects.get(workspace_id=workspace_id) + + if general_settings.auto_map_employees and general_settings.corporate_credit_card_expenses_object != 'BILL': + start_datetime = datetime.now() + + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.async_auto_map_ccc_account', + args='{0}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.async_auto_map_ccc_account', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_bill_payment_creation(sync_fyle_to_qbo_payments, workspace_id): + general_mappings: GeneralMapping = GeneralMapping.objects.filter(workspace_id=workspace_id).first() + if general_mappings: + if sync_fyle_to_qbo_payments and general_mappings.bill_payment_account_id: + start_datetime = datetime.now() + schedule, _ = Schedule.objects.update_or_create( + func='apps.quickbooks_online.tasks.create_bill_payment', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + if not sync_fyle_to_qbo_payments: + schedule: Schedule = Schedule.objects.filter( + func='apps.quickbooks_online.tasks.create_bill_payment', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_qbo_objects_status_sync(sync_qbo_to_fyle_payments, workspace_id): + if sync_qbo_to_fyle_payments: + start_datetime = datetime.now() + schedule, _ = Schedule.objects.update_or_create( + func='apps.quickbooks_online.tasks.check_qbo_object_status', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.quickbooks_online.tasks.check_qbo_object_status', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + +def schedule_reimbursements_sync(sync_qbo_to_fyle_payments, workspace_id): + if sync_qbo_to_fyle_payments: + start_datetime = datetime.now() + timedelta(hours=12) + schedule, _ = Schedule.objects.update_or_create( + func='apps.quickbooks_online.tasks.process_reimbursements', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.quickbooks_online.tasks.process_reimbursements', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_email_notification(workspace_id: int, schedule_enabled: bool, hours: int): + if schedule_enabled: + schedule, _ = Schedule.objects.update_or_create( + func='apps.workspaces.tasks.run_email_notification', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': hours * 60, + 'next_run': datetime.now() + timedelta(minutes=10) + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.workspaces.tasks.run_email_notification', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + +def schedule_bills_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule bills creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, bill__id__isnull=True, exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_BILL' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_BILL' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_bill', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() + +def schedule_cheques_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule cheque creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, cheque__id__isnull=True, exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_CHECK' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_CHECK' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_cheque', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() + +def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule QBO expense creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, qboexpense__id__isnull=True, exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else 'CREATING_DEBIT_CARD_EXPENSE' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else 'CREATING_DEBIT_CARD_EXPENSE' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_qbo_expense', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() + +def schedule_credit_card_purchase_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule credit card purchase creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, creditcardpurchase__id__isnull=True, + exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_CREDIT_CARD_PURCHASE' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_CREDIT_CARD_PURCHASE' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_credit_card_purchase', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() + +def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule journal_entry creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, journalentry__id__isnull=True, exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_JOURNAL_ENTRY' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_JOURNAL_ENTRY' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_journal_entry', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() diff --git a/tests/test_mappings/test_tasks.py b/tests/test_mappings/test_tasks.py index 4c1b2046..d3760605 100644 --- a/tests/test_mappings/test_tasks.py +++ b/tests/test_mappings/test_tasks.py @@ -8,6 +8,7 @@ from fyle_accounting_mappings.models import DestinationAttribute, ExpenseAttribute, CategoryMapping, \ Mapping, MappingSetting, EmployeeMapping from apps.mappings.tasks import * +from fyle_qbo_api.queue import * from fyle_integrations_platform_connector import PlatformConnector from apps.mappings.models import GeneralMapping from .fixtures import data diff --git a/tests/test_quickbooks_online/test_tasks.py b/tests/test_quickbooks_online/test_tasks.py index aa56fe72..d7aa56f6 100644 --- a/tests/test_quickbooks_online/test_tasks.py +++ b/tests/test_quickbooks_online/test_tasks.py @@ -19,6 +19,7 @@ from apps.quickbooks_online.utils import QBOConnector from apps.quickbooks_online.exceptions import handle_quickbooks_error from .fixtures import data +from fyle_qbo_api.queue import * logger = logging.getLogger(__name__) From 407710c84bfc8cd50312c0e783fe9a7ab1173ce3 Mon Sep 17 00:00:00 2001 From: ruuushhh Date: Mon, 26 Jun 2023 12:19:46 +0530 Subject: [PATCH 2/5] Codefactor fixed --- apps/mappings/tasks.py | 7 ------ apps/quickbooks_online/tasks.py | 5 +---- apps/workspaces/tasks.py | 6 +++--- apps/workspaces/utils.py | 10 +++------ fyle_qbo_api/queue.py | 25 ++++++++++++++-------- tests/test_quickbooks_online/test_tasks.py | 3 ++- 6 files changed, 25 insertions(+), 31 deletions(-) diff --git a/apps/mappings/tasks.py b/apps/mappings/tasks.py index 6ad8cdb1..38c2b53b 100644 --- a/apps/mappings/tasks.py +++ b/apps/mappings/tasks.py @@ -2,16 +2,9 @@ import traceback from django.db.models import Q from dateutil import parser -from datetime import datetime, timedelta - from typing import List, Dict -from django_q.models import Schedule from django_q.tasks import Chain - -from qbosdk.exceptions import WrongParamsError as QBOWrongParamsError, InvalidTokenError - -from fyle.platform.exceptions import WrongParamsError, InvalidTokenError as FyleInvalidTokenError from fyle_integrations_platform_connector import PlatformConnector from fyle_accounting_mappings.models import MappingSetting, Mapping, DestinationAttribute, ExpenseAttribute,\ EmployeeMapping diff --git a/apps/quickbooks_online/tasks.py b/apps/quickbooks_online/tasks.py index d78fa5a6..a28cedf8 100644 --- a/apps/quickbooks_online/tasks.py +++ b/apps/quickbooks_online/tasks.py @@ -1,13 +1,10 @@ import logging import json import traceback -from typing import List -from datetime import datetime, timedelta +from datetime import datetime from django.db import transaction from django.db.models import Q -from django_q.tasks import Chain -from django_q.models import Schedule from qbosdk.exceptions import WrongParamsError, InvalidTokenError diff --git a/apps/workspaces/tasks.py b/apps/workspaces/tasks.py index 7b56dff6..c8b920c1 100644 --- a/apps/workspaces/tasks.py +++ b/apps/workspaces/tasks.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta, date +from datetime import datetime, date from typing import List import logging @@ -12,9 +12,9 @@ from fyle_qbo_api.queue import (schedule_email_notification, schedule_bills_creation, schedule_cheques_creation, schedule_journal_entry_creation, schedule_credit_card_purchase_creation, schedule_qbo_expense_creation) -from apps.workspaces.models import User, Workspace, WorkspaceSchedule, WorkspaceGeneralSettings, LastExportDetail, QBOCredential, FyleCredential +from apps.workspaces.models import Workspace, WorkspaceSchedule, WorkspaceGeneralSettings, LastExportDetail, QBOCredential, FyleCredential from apps.fyle.tasks import async_create_expense_groups -from apps.fyle.models import Expense, ExpenseGroup +from apps.fyle.models import ExpenseGroup from apps.tasks.models import TaskLog from fyle_accounting_mappings.models import ExpenseAttribute diff --git a/apps/workspaces/utils.py b/apps/workspaces/utils.py index 29ade528..fdeb07ed 100644 --- a/apps/workspaces/utils.py +++ b/apps/workspaces/utils.py @@ -1,24 +1,20 @@ import json import base64 from typing import Dict - import requests from django.conf import settings -from django.db.models import Q from future.moves.urllib.parse import urlencode from qbosdk import UnauthorizedClientError, NotFoundClientError, WrongParamsError, InternalServerError from fyle_accounting_mappings.models import MappingSetting -from fyle_qbo_api.queue import (schedule_tax_groups_creation, schedule_auto_map_employees, - schedule_auto_map_ccc_employees, schedule_bill_payment_creation, - schedule_qbo_objects_status_sync, schedule_reimbursements_sync) +from fyle_qbo_api.queue import (schedule_tax_groups_creation, schedule_auto_map_employees, schedule_auto_map_ccc_employees, + schedule_bill_payment_creation, schedule_qbo_objects_status_sync, schedule_reimbursements_sync) from fyle_qbo_api.utils import assert_valid -from .models import WorkspaceGeneralSettings, LastExportDetail +from .models import WorkspaceGeneralSettings from ..fyle.models import ExpenseGroupSettings -from ..tasks.models import TaskLog def generate_qbo_refresh_token(authorization_code: str, redirect_uri: str) -> str: diff --git a/fyle_qbo_api/queue.py b/fyle_qbo_api/queue.py index ed5545f7..375d79bf 100644 --- a/fyle_qbo_api/queue.py +++ b/fyle_qbo_api/queue.py @@ -1,14 +1,17 @@ from datetime import datetime, timedelta +from typing import List + + from django_q.models import Schedule from django_q.tasks import Chain -from typing import List from django.db.models import Q -from apps.tasks.models import Error, TaskLog -from apps.mappings.models import GeneralMapping -from apps.workspaces.models import WorkspaceGeneralSettings, FyleCredential + from fyle_accounting_mappings.models import MappingSetting -from apps.fyle.models import Expense, ExpenseGroup +from apps.tasks.models import TaskLog +from apps.mappings.models import GeneralMapping +from apps.workspaces.models import WorkspaceGeneralSettings, FyleCredential +from apps.fyle.models import ExpenseGroup def schedule_cost_centers_creation(import_to_fyle, workspace_id): @@ -318,11 +321,13 @@ def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str expense_group=expense_group, defaults={ 'status': 'ENQUEUED', - 'type': 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else 'CREATING_DEBIT_CARD_EXPENSE' + 'type': 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else + 'CREATING_DEBIT_CARD_EXPENSE' } ) if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else 'CREATING_DEBIT_CARD_EXPENSE' + task_log.type = 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else \ + 'CREATING_DEBIT_CARD_EXPENSE' task_log.status = 'ENQUEUED' task_log.save() @@ -372,7 +377,8 @@ def schedule_credit_card_purchase_creation(workspace_id: int, expense_group_ids: if expense_groups.count() == index + 1: last_export = True - chain.append('apps.quickbooks_online.tasks.create_credit_card_purchase', expense_group, task_log.id, last_export) + chain.append('apps.quickbooks_online.tasks.create_credit_card_purchase', expense_group, task_log.id, + last_export) if chain.length() > 1: chain.run() @@ -387,7 +393,8 @@ def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[s if expense_group_ids: expense_groups = ExpenseGroup.objects.filter( Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, journalentry__id__isnull=True, exported_at__isnull=True + workspace_id=workspace_id, id__in=expense_group_ids, journalentry__id__isnull=True, + exported_at__isnull=True ).all() chain = Chain() diff --git a/tests/test_quickbooks_online/test_tasks.py b/tests/test_quickbooks_online/test_tasks.py index d7aa56f6..ed28fe26 100644 --- a/tests/test_quickbooks_online/test_tasks.py +++ b/tests/test_quickbooks_online/test_tasks.py @@ -10,6 +10,7 @@ from apps.quickbooks_online.models import * from apps.quickbooks_online.tasks import __validate_expense_group from apps.quickbooks_online.tasks import * +from fyle_qbo_api.queue import * from fyle_qbo_api.exceptions import BulkError from qbosdk.exceptions import WrongParamsError from fyle_accounting_mappings.models import EmployeeMapping @@ -19,7 +20,7 @@ from apps.quickbooks_online.utils import QBOConnector from apps.quickbooks_online.exceptions import handle_quickbooks_error from .fixtures import data -from fyle_qbo_api.queue import * + logger = logging.getLogger(__name__) From e7aa85fe8aeadcf5accbe77702bdf182041cf4b2 Mon Sep 17 00:00:00 2001 From: ruuushhh Date: Mon, 26 Jun 2023 12:27:08 +0530 Subject: [PATCH 3/5] test cases resolved --- apps/mappings/tasks.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/mappings/tasks.py b/apps/mappings/tasks.py index 38c2b53b..21984256 100644 --- a/apps/mappings/tasks.py +++ b/apps/mappings/tasks.py @@ -5,6 +5,8 @@ from typing import List, Dict from django_q.tasks import Chain +from qbosdk.exceptions import WrongParamsError as QBOWrongParamsError, InvalidTokenError +from fyle.platform.exceptions import WrongParamsError, InvalidTokenError as FyleInvalidTokenError from fyle_integrations_platform_connector import PlatformConnector from fyle_accounting_mappings.models import MappingSetting, Mapping, DestinationAttribute, ExpenseAttribute,\ EmployeeMapping From fc93808a00afe55a06d7116bc7f96c49463b0b94 Mon Sep 17 00:00:00 2001 From: ruuushhh Date: Tue, 27 Jun 2023 13:55:01 +0530 Subject: [PATCH 4/5] comments resolved --- apps/fyle/tasks.py | 1 - apps/mappings/queue.py | 111 ++++++ apps/mappings/signals.py | 10 +- apps/mappings/utils.py | 2 +- .../apis/advanced_configurations/triggers.py | 5 +- .../apis/export_settings/triggers.py | 4 +- .../apis/import_settings/triggers.py | 9 +- .../workspaces/apis/map_employees/triggers.py | 2 +- {fyle_qbo_api => apps/workspaces}/queue.py | 321 +++++++----------- apps/workspaces/signals.py | 8 +- apps/workspaces/tasks.py | 5 +- apps/workspaces/utils.py | 9 +- tests/test_mappings/test_tasks.py | 3 +- tests/test_quickbooks_online/test_tasks.py | 3 +- 14 files changed, 257 insertions(+), 236 deletions(-) create mode 100644 apps/mappings/queue.py rename {fyle_qbo_api => apps/workspaces}/queue.py (76%) diff --git a/apps/fyle/tasks.py b/apps/fyle/tasks.py index 8e1d8f00..a63efa0a 100644 --- a/apps/fyle/tasks.py +++ b/apps/fyle/tasks.py @@ -4,7 +4,6 @@ from datetime import datetime from django.db import transaction -from django_q.tasks import async_task from fyle_integrations_platform_connector import PlatformConnector from fyle.platform.exceptions import InvalidTokenError as FyleInvalidTokenError diff --git a/apps/mappings/queue.py b/apps/mappings/queue.py new file mode 100644 index 00000000..702a0707 --- /dev/null +++ b/apps/mappings/queue.py @@ -0,0 +1,111 @@ +from datetime import datetime, timedelta +from django_q.tasks import async_task +from fyle_accounting_mappings.models import MappingSetting + +from django_q.models import Schedule + +from apps.mappings.models import GeneralMapping +from apps.workspaces.models import WorkspaceGeneralSettings + + +def async_auto_create_expense_field_mapping(instance: MappingSetting): + async_task( + 'apps.mappings.tasks.auto_create_expense_fields_mappings', + int(instance.workspace_id), + instance.destination_field, + instance.source_field + ) + + +def schedule_cost_centers_creation(import_to_fyle, workspace_id): + if import_to_fyle: + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.auto_create_cost_center_mappings', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': datetime.now() + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.auto_create_cost_center_mappings', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_fyle_attributes_creation(workspace_id: int): + mapping_settings = MappingSetting.objects.filter( + is_custom=True, import_to_fyle=True, workspace_id=workspace_id + ).all() + if mapping_settings: + schedule, _ = Schedule.objects.get_or_create( + func='apps.mappings.tasks.async_auto_create_custom_field_mappings', + args='{0}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': datetime.now() + timedelta(hours=24) + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.async_auto_create_custom_field_mappings', + args='{0}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_bill_payment_creation(sync_fyle_to_qbo_payments, workspace_id): + general_mappings: GeneralMapping = GeneralMapping.objects.filter(workspace_id=workspace_id).first() + if general_mappings: + if sync_fyle_to_qbo_payments and general_mappings.bill_payment_account_id: + start_datetime = datetime.now() + schedule, _ = Schedule.objects.update_or_create( + func='apps.quickbooks_online.tasks.create_bill_payment', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + if not sync_fyle_to_qbo_payments: + schedule: Schedule = Schedule.objects.filter( + func='apps.quickbooks_online.tasks.create_bill_payment', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_auto_map_ccc_employees(workspace_id: int): + general_settings = WorkspaceGeneralSettings.objects.get(workspace_id=workspace_id) + + if general_settings.auto_map_employees and general_settings.corporate_credit_card_expenses_object != 'BILL': + start_datetime = datetime.now() + + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.async_auto_map_ccc_account', + args='{0}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.async_auto_map_ccc_account', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() diff --git a/apps/mappings/signals.py b/apps/mappings/signals.py index 6a7294a5..81f7bf26 100644 --- a/apps/mappings/signals.py +++ b/apps/mappings/signals.py @@ -3,12 +3,10 @@ """ from django.db.models.signals import post_save, pre_save, post_delete from django.dispatch import receiver -from django_q.tasks import async_task from fyle_accounting_mappings.models import MappingSetting, Mapping, EmployeeMapping from apps.tasks.models import Error -from fyle_qbo_api.queue import schedule_cost_centers_creation, schedule_fyle_attributes_creation from apps.mappings.tasks import upload_attributes_to_fyle from apps.workspaces.utils import delete_cards_mapping_settings from apps.workspaces.models import WorkspaceGeneralSettings @@ -16,6 +14,7 @@ from apps.workspaces.apis.import_settings.triggers import ImportSettingsTrigger from .helpers import schedule_or_delete_fyle_import_tasks +from .queue import async_auto_create_expense_field_mapping, schedule_cost_centers_creation, schedule_fyle_attributes_creation @receiver(post_save, sender=Mapping) @@ -90,12 +89,7 @@ def run_pre_mapping_settings_triggers(sender, instance: MappingSetting, **kwargs source_placeholder=instance.source_placeholder, ) - async_task( - 'apps.mappings.tasks.auto_create_expense_fields_mappings', - int(instance.workspace_id), - instance.destination_field, - instance.source_field - ) + async_auto_create_expense_field_mapping(instance) @receiver(post_delete, sender=MappingSetting) def run_post_delete_mapping_settings_triggers(sender, instance: MappingSetting, **kwargs): diff --git a/apps/mappings/utils.py b/apps/mappings/utils.py index 052e4272..dae432ea 100644 --- a/apps/mappings/utils.py +++ b/apps/mappings/utils.py @@ -2,11 +2,11 @@ from django.db.models import Q -from fyle_qbo_api.queue import schedule_bill_payment_creation, schedule_auto_map_ccc_employees from apps.workspaces.models import WorkspaceGeneralSettings from fyle_qbo_api.utils import assert_valid from .models import GeneralMapping +from .queue import schedule_bill_payment_creation, schedule_auto_map_ccc_employees class MappingUtils: diff --git a/apps/workspaces/apis/advanced_configurations/triggers.py b/apps/workspaces/apis/advanced_configurations/triggers.py index d381323b..e75dcaed 100644 --- a/apps/workspaces/apis/advanced_configurations/triggers.py +++ b/apps/workspaces/apis/advanced_configurations/triggers.py @@ -1,7 +1,6 @@ from apps.workspaces.models import WorkspaceGeneralSettings -from fyle_qbo_api.queue import (schedule_bill_payment_creation, schedule_qbo_objects_status_sync, - schedule_reimbursements_sync) - +from apps.workspaces.queue import schedule_qbo_objects_status_sync, schedule_reimbursements_sync +from apps.mappings.queue import schedule_bill_payment_creation class AdvancedConfigurationsTriggers: diff --git a/apps/workspaces/apis/export_settings/triggers.py b/apps/workspaces/apis/export_settings/triggers.py index e97262ef..12c0f426 100644 --- a/apps/workspaces/apis/export_settings/triggers.py +++ b/apps/workspaces/apis/export_settings/triggers.py @@ -1,7 +1,7 @@ from typing import Dict -from django_q.tasks import async_task from apps.workspaces.models import WorkspaceGeneralSettings +from apps.workspaces.queue import async_disable_category_for_items_mapping class ExportSettingsTrigger: def __init__(self, workspace_general_settings: Dict, workspace_id: int): @@ -22,4 +22,4 @@ def post_save_workspace_general_settings(self): # Disable category for items mapping and set import-items to flase workspace_general_settings.import_items = False workspace_general_settings.save() - async_task('apps.mappings.tasks.disable_category_for_items_mapping', self.__workspace_id) + async_disable_category_for_items_mapping(self.__workspace_id) diff --git a/apps/workspaces/apis/import_settings/triggers.py b/apps/workspaces/apis/import_settings/triggers.py index 7c42596b..dcb00046 100644 --- a/apps/workspaces/apis/import_settings/triggers.py +++ b/apps/workspaces/apis/import_settings/triggers.py @@ -2,15 +2,14 @@ from datetime import timedelta from django.db.models import Q -from django_q.models import Schedule -from django_q.tasks import async_task + from fyle_accounting_mappings.models import MappingSetting from apps.fyle.models import ExpenseGroupSettings from apps.mappings.helpers import schedule_or_delete_fyle_import_tasks from apps.workspaces.models import WorkspaceGeneralSettings -from fyle_qbo_api.queue import schedule_cost_centers_creation, schedule_fyle_attributes_creation, schedule_tax_groups_creation - +from apps.workspaces.queue import schedule_tax_groups_creation, async_disable_category_for_items_mapping +from apps.mappings.queue import schedule_cost_centers_creation, schedule_fyle_attributes_creation class ImportSettingsTrigger: """ @@ -88,7 +87,7 @@ def post_save_workspace_general_settings(self, workspace_general_settings_instan schedule_or_delete_fyle_import_tasks(workspace_general_settings_instance) if not workspace_general_settings_instance.import_items: - async_task('apps.mappings.tasks.disable_category_for_items_mapping', self.__workspace_id) + async_disable_category_for_items_mapping(self.__workspace_id) def __remove_old_department_source_field( diff --git a/apps/workspaces/apis/map_employees/triggers.py b/apps/workspaces/apis/map_employees/triggers.py index c16d4233..11c549fa 100644 --- a/apps/workspaces/apis/map_employees/triggers.py +++ b/apps/workspaces/apis/map_employees/triggers.py @@ -1,4 +1,4 @@ -from fyle_qbo_api.queue import schedule_auto_map_employees +from apps.workspaces.queue import schedule_auto_map_employees from apps.workspaces.models import WorkspaceGeneralSettings diff --git a/fyle_qbo_api/queue.py b/apps/workspaces/queue.py similarity index 76% rename from fyle_qbo_api/queue.py rename to apps/workspaces/queue.py index 375d79bf..5ce57dce 100644 --- a/fyle_qbo_api/queue.py +++ b/apps/workspaces/queue.py @@ -1,199 +1,23 @@ from datetime import datetime, timedelta from typing import List - -from django_q.models import Schedule -from django_q.tasks import Chain +from django_q.tasks import Chain, async_task from django.db.models import Q - -from fyle_accounting_mappings.models import MappingSetting +from django_q.models import Schedule from apps.tasks.models import TaskLog -from apps.mappings.models import GeneralMapping -from apps.workspaces.models import WorkspaceGeneralSettings, FyleCredential -from apps.fyle.models import ExpenseGroup - - -def schedule_cost_centers_creation(import_to_fyle, workspace_id): - if import_to_fyle: - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.auto_create_cost_center_mappings', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': datetime.now() - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.auto_create_cost_center_mappings', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - -def schedule_fyle_attributes_creation(workspace_id: int): - mapping_settings = MappingSetting.objects.filter( - is_custom=True, import_to_fyle=True, workspace_id=workspace_id - ).all() - if mapping_settings: - schedule, _ = Schedule.objects.get_or_create( - func='apps.mappings.tasks.async_auto_create_custom_field_mappings', - args='{0}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': datetime.now() + timedelta(hours=24) - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.async_auto_create_custom_field_mappings', - args='{0}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - -def schedule_tax_groups_creation(import_tax_codes, workspace_id): - if import_tax_codes: - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.auto_create_tax_codes_mappings', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': datetime.now() - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.auto_create_tax_codes_mappings', - args='{}'.format(workspace_id), - ).first() - - if schedule: - schedule.delete() - - -def schedule_auto_map_employees(employee_mapping_preference: str, workspace_id: int): - if employee_mapping_preference: - start_datetime = datetime.now() - - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.async_auto_map_employees', - args='{0}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.async_auto_map_employees', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - -def schedule_auto_map_ccc_employees(workspace_id: int): - general_settings = WorkspaceGeneralSettings.objects.get(workspace_id=workspace_id) - - if general_settings.auto_map_employees and general_settings.corporate_credit_card_expenses_object != 'BILL': - start_datetime = datetime.now() - - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.async_auto_map_ccc_account', - args='{0}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.async_auto_map_ccc_account', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - -def schedule_bill_payment_creation(sync_fyle_to_qbo_payments, workspace_id): - general_mappings: GeneralMapping = GeneralMapping.objects.filter(workspace_id=workspace_id).first() - if general_mappings: - if sync_fyle_to_qbo_payments and general_mappings.bill_payment_account_id: - start_datetime = datetime.now() - schedule, _ = Schedule.objects.update_or_create( - func='apps.quickbooks_online.tasks.create_bill_payment', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - if not sync_fyle_to_qbo_payments: - schedule: Schedule = Schedule.objects.filter( - func='apps.quickbooks_online.tasks.create_bill_payment', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - -def schedule_qbo_objects_status_sync(sync_qbo_to_fyle_payments, workspace_id): - if sync_qbo_to_fyle_payments: - start_datetime = datetime.now() - schedule, _ = Schedule.objects.update_or_create( - func='apps.quickbooks_online.tasks.check_qbo_object_status', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.quickbooks_online.tasks.check_qbo_object_status', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - -def schedule_reimbursements_sync(sync_qbo_to_fyle_payments, workspace_id): - if sync_qbo_to_fyle_payments: - start_datetime = datetime.now() + timedelta(hours=12) - schedule, _ = Schedule.objects.update_or_create( - func='apps.quickbooks_online.tasks.process_reimbursements', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.quickbooks_online.tasks.process_reimbursements', - args='{}'.format(workspace_id) - ).first() +from apps.workspaces.models import FyleCredential, WorkspaceGeneralSettings +from apps.fyle.models import ExpenseGroup - if schedule: - schedule.delete() +def async_run_post_configration_triggers(instance:WorkspaceGeneralSettings): + async_task( + 'apps.quickbooks_online.tasks.async_sync_accounts', + int(instance.workspace_id) + ) +def async_disable_category_for_items_mapping(workspace_id: int): + async_task('apps.mappings.tasks.disable_category_for_items_mapping', workspace_id) def schedule_email_notification(workspace_id: int, schedule_enabled: bool, hours: int): if schedule_enabled: @@ -215,6 +39,7 @@ def schedule_email_notification(workspace_id: int, schedule_enabled: bool, hours if schedule: schedule.delete() + def schedule_bills_creation(workspace_id: int, expense_group_ids: List[str]): """ Schedule bills creation @@ -256,6 +81,7 @@ def schedule_bills_creation(workspace_id: int, expense_group_ids: List[str]): if chain.length() > 1: chain.run() + def schedule_cheques_creation(workspace_id: int, expense_group_ids: List[str]): """ Schedule cheque creation @@ -297,9 +123,10 @@ def schedule_cheques_creation(workspace_id: int, expense_group_ids: List[str]): if chain.length() > 1: chain.run() -def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str]): + +def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[str]): """ - Schedule QBO expense creation + Schedule journal_entry creation :param expense_group_ids: List of expense group ids :param workspace_id: workspace id :return: None @@ -307,7 +134,8 @@ def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str if expense_group_ids: expense_groups = ExpenseGroup.objects.filter( Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, qboexpense__id__isnull=True, exported_at__isnull=True + workspace_id=workspace_id, id__in=expense_group_ids, journalentry__id__isnull=True, + exported_at__isnull=True ).all() chain = Chain() @@ -321,13 +149,11 @@ def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str expense_group=expense_group, defaults={ 'status': 'ENQUEUED', - 'type': 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else - 'CREATING_DEBIT_CARD_EXPENSE' + 'type': 'CREATING_JOURNAL_ENTRY' } ) if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else \ - 'CREATING_DEBIT_CARD_EXPENSE' + task_log.type = 'CREATING_JOURNAL_ENTRY' task_log.status = 'ENQUEUED' task_log.save() @@ -335,11 +161,12 @@ def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str if expense_groups.count() == index + 1: last_export = True - chain.append('apps.quickbooks_online.tasks.create_qbo_expense', expense_group, task_log.id, last_export) + chain.append('apps.quickbooks_online.tasks.create_journal_entry', expense_group, task_log.id, last_export) if chain.length() > 1: chain.run() + def schedule_credit_card_purchase_creation(workspace_id: int, expense_group_ids: List[str]): """ Schedule credit card purchase creation @@ -383,9 +210,10 @@ def schedule_credit_card_purchase_creation(workspace_id: int, expense_group_ids: if chain.length() > 1: chain.run() -def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[str]): + +def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str]): """ - Schedule journal_entry creation + Schedule QBO expense creation :param expense_group_ids: List of expense group ids :param workspace_id: workspace id :return: None @@ -393,8 +221,7 @@ def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[s if expense_group_ids: expense_groups = ExpenseGroup.objects.filter( Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, journalentry__id__isnull=True, - exported_at__isnull=True + workspace_id=workspace_id, id__in=expense_group_ids, qboexpense__id__isnull=True, exported_at__isnull=True ).all() chain = Chain() @@ -408,11 +235,13 @@ def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[s expense_group=expense_group, defaults={ 'status': 'ENQUEUED', - 'type': 'CREATING_JOURNAL_ENTRY' + 'type': 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else + 'CREATING_DEBIT_CARD_EXPENSE' } ) if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_JOURNAL_ENTRY' + task_log.type = 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else \ + 'CREATING_DEBIT_CARD_EXPENSE' task_log.status = 'ENQUEUED' task_log.save() @@ -420,7 +249,95 @@ def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[s if expense_groups.count() == index + 1: last_export = True - chain.append('apps.quickbooks_online.tasks.create_journal_entry', expense_group, task_log.id, last_export) + chain.append('apps.quickbooks_online.tasks.create_qbo_expense', expense_group, task_log.id, last_export) if chain.length() > 1: chain.run() + + +def schedule_qbo_objects_status_sync(sync_qbo_to_fyle_payments, workspace_id): + if sync_qbo_to_fyle_payments: + start_datetime = datetime.now() + schedule, _ = Schedule.objects.update_or_create( + func='apps.quickbooks_online.tasks.check_qbo_object_status', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.quickbooks_online.tasks.check_qbo_object_status', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_reimbursements_sync(sync_qbo_to_fyle_payments, workspace_id): + if sync_qbo_to_fyle_payments: + start_datetime = datetime.now() + timedelta(hours=12) + schedule, _ = Schedule.objects.update_or_create( + func='apps.quickbooks_online.tasks.process_reimbursements', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.quickbooks_online.tasks.process_reimbursements', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_tax_groups_creation(import_tax_codes, workspace_id): + if import_tax_codes: + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.auto_create_tax_codes_mappings', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': datetime.now() + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.auto_create_tax_codes_mappings', + args='{}'.format(workspace_id), + ).first() + + if schedule: + schedule.delete() + + +def schedule_auto_map_employees(employee_mapping_preference: str, workspace_id: int): + if employee_mapping_preference: + start_datetime = datetime.now() + + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.async_auto_map_employees', + args='{0}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.async_auto_map_employees', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() diff --git a/apps/workspaces/signals.py b/apps/workspaces/signals.py index 197ce2f0..6b2d594f 100644 --- a/apps/workspaces/signals.py +++ b/apps/workspaces/signals.py @@ -3,13 +3,12 @@ """ from django.db.models.signals import post_save from django.dispatch import receiver -from django_q.tasks import async_task from fyle_accounting_mappings.models import DestinationAttribute, EmployeeMapping from apps.workspaces.models import Workspace, WorkspaceGeneralSettings from apps.workspaces.utils import delete_cards_mapping_settings - +from .queue import async_run_post_configration_triggers @receiver(post_save, sender=WorkspaceGeneralSettings) def run_post_configration_triggers(sender, instance: WorkspaceGeneralSettings, **kwargs): @@ -18,10 +17,7 @@ def run_post_configration_triggers(sender, instance: WorkspaceGeneralSettings, * :param instance: Row Instance of Sender Class :return: None """ - async_task( - 'apps.quickbooks_online.tasks.async_sync_accounts', - int(instance.workspace_id) - ) + async_run_post_configration_triggers(instance) delete_cards_mapping_settings(instance) diff --git a/apps/workspaces/tasks.py b/apps/workspaces/tasks.py index c8b920c1..091a1aef 100644 --- a/apps/workspaces/tasks.py +++ b/apps/workspaces/tasks.py @@ -10,8 +10,6 @@ from django_q.models import Schedule from django.utils.safestring import mark_safe -from fyle_qbo_api.queue import (schedule_email_notification, schedule_bills_creation, schedule_cheques_creation, - schedule_journal_entry_creation, schedule_credit_card_purchase_creation, schedule_qbo_expense_creation) from apps.workspaces.models import Workspace, WorkspaceSchedule, WorkspaceGeneralSettings, LastExportDetail, QBOCredential, FyleCredential from apps.fyle.tasks import async_create_expense_groups from apps.fyle.models import ExpenseGroup @@ -20,6 +18,9 @@ from fyle_accounting_mappings.models import ExpenseAttribute from apps.tasks.models import Error +from .queue import (schedule_email_notification, schedule_bills_creation, schedule_cheques_creation, + schedule_journal_entry_creation, schedule_credit_card_purchase_creation, schedule_qbo_expense_creation) + logger = logging.getLogger(__name__) logger.level = logging.INFO diff --git a/apps/workspaces/utils.py b/apps/workspaces/utils.py index fdeb07ed..3fed3a0b 100644 --- a/apps/workspaces/utils.py +++ b/apps/workspaces/utils.py @@ -9,13 +9,14 @@ from qbosdk import UnauthorizedClientError, NotFoundClientError, WrongParamsError, InternalServerError from fyle_accounting_mappings.models import MappingSetting -from fyle_qbo_api.queue import (schedule_tax_groups_creation, schedule_auto_map_employees, schedule_auto_map_ccc_employees, - schedule_bill_payment_creation, schedule_qbo_objects_status_sync, schedule_reimbursements_sync) + from fyle_qbo_api.utils import assert_valid from .models import WorkspaceGeneralSettings from ..fyle.models import ExpenseGroupSettings - +from .queue import (schedule_tax_groups_creation, schedule_auto_map_employees, schedule_qbo_objects_status_sync, + schedule_reimbursements_sync) +from apps.mappings.queue import schedule_auto_map_ccc_employees, schedule_bill_payment_creation def generate_qbo_refresh_token(authorization_code: str, redirect_uri: str) -> str: """ @@ -185,3 +186,5 @@ def delete_cards_mapping_settings(workspace_general_settings: WorkspaceGeneralSe ).first() if mapping_setting: mapping_setting.delete() + + diff --git a/tests/test_mappings/test_tasks.py b/tests/test_mappings/test_tasks.py index d3760605..e391c861 100644 --- a/tests/test_mappings/test_tasks.py +++ b/tests/test_mappings/test_tasks.py @@ -8,7 +8,8 @@ from fyle_accounting_mappings.models import DestinationAttribute, ExpenseAttribute, CategoryMapping, \ Mapping, MappingSetting, EmployeeMapping from apps.mappings.tasks import * -from fyle_qbo_api.queue import * +from apps.mappings.queue import * +from apps.workspaces.queue import * from fyle_integrations_platform_connector import PlatformConnector from apps.mappings.models import GeneralMapping from .fixtures import data diff --git a/tests/test_quickbooks_online/test_tasks.py b/tests/test_quickbooks_online/test_tasks.py index ed28fe26..eae58383 100644 --- a/tests/test_quickbooks_online/test_tasks.py +++ b/tests/test_quickbooks_online/test_tasks.py @@ -10,7 +10,8 @@ from apps.quickbooks_online.models import * from apps.quickbooks_online.tasks import __validate_expense_group from apps.quickbooks_online.tasks import * -from fyle_qbo_api.queue import * +from apps.workspaces.queue import * +from apps.mappings.queue import * from fyle_qbo_api.exceptions import BulkError from qbosdk.exceptions import WrongParamsError from fyle_accounting_mappings.models import EmployeeMapping From b7ff1e172645aa770cb3c8aaa05ca8dd1703e505 Mon Sep 17 00:00:00 2001 From: ruuushhh Date: Wed, 28 Jun 2023 13:04:31 +0530 Subject: [PATCH 5/5] comments resolved --- apps/mappings/queue.py | 55 ++- apps/mappings/utils.py | 84 ----- apps/mappings/views.py | 4 - apps/quickbooks_online/queue.py | 276 +++++++++++++++ .../apis/advanced_configurations/triggers.py | 2 +- .../apis/export_settings/triggers.py | 2 +- .../apis/import_settings/triggers.py | 4 +- .../workspaces/apis/map_employees/triggers.py | 2 +- apps/workspaces/queue.py | 321 +----------------- apps/workspaces/signals.py | 2 +- apps/workspaces/tasks.py | 5 +- apps/workspaces/utils.py | 6 +- tests/test_quickbooks_online/test_tasks.py | 1 + 13 files changed, 341 insertions(+), 423 deletions(-) delete mode 100644 apps/mappings/utils.py create mode 100644 apps/quickbooks_online/queue.py diff --git a/apps/mappings/queue.py b/apps/mappings/queue.py index 702a0707..316a0a81 100644 --- a/apps/mappings/queue.py +++ b/apps/mappings/queue.py @@ -8,12 +8,12 @@ from apps.workspaces.models import WorkspaceGeneralSettings -def async_auto_create_expense_field_mapping(instance: MappingSetting): +def async_auto_create_expense_field_mapping(mapping_setting: MappingSetting): async_task( 'apps.mappings.tasks.auto_create_expense_fields_mappings', - int(instance.workspace_id), - instance.destination_field, - instance.source_field + int(mapping_setting.workspace_id), + mapping_setting.destination_field, + mapping_setting.source_field ) @@ -109,3 +109,50 @@ def schedule_auto_map_ccc_employees(workspace_id: int): if schedule: schedule.delete() + +def schedule_tax_groups_creation(import_tax_codes, workspace_id): + if import_tax_codes: + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.auto_create_tax_codes_mappings', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': datetime.now() + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.auto_create_tax_codes_mappings', + args='{}'.format(workspace_id), + ).first() + + if schedule: + schedule.delete() + + +def schedule_auto_map_employees(employee_mapping_preference: str, workspace_id: int): + if employee_mapping_preference: + start_datetime = datetime.now() + + schedule, _ = Schedule.objects.update_or_create( + func='apps.mappings.tasks.async_auto_map_employees', + args='{0}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.mappings.tasks.async_auto_map_employees', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def async_disable_category_for_items_mapping(workspace_id: int): + async_task('apps.mappings.tasks.disable_category_for_items_mapping', workspace_id) diff --git a/apps/mappings/utils.py b/apps/mappings/utils.py deleted file mode 100644 index dae432ea..00000000 --- a/apps/mappings/utils.py +++ /dev/null @@ -1,84 +0,0 @@ -from typing import Dict - -from django.db.models import Q - -from apps.workspaces.models import WorkspaceGeneralSettings -from fyle_qbo_api.utils import assert_valid - -from .models import GeneralMapping -from .queue import schedule_bill_payment_creation, schedule_auto_map_ccc_employees - - -class MappingUtils: - def __init__(self, workspace_id): - self.__workspace_id = workspace_id - - def create_or_update_general_mapping(self, general_mapping: Dict): - """ - Create or update general mapping - :param general_mapping: general mapping payload - :return: - """ - general_settings = WorkspaceGeneralSettings.objects.get(workspace_id=self.__workspace_id) - - if (general_settings.employee_field_mapping == 'VENDOR' and \ - general_settings.reimbursable_expenses_object == 'JOURNAL ENTRY') or \ - (general_settings.corporate_credit_card_expenses_object == 'BILL' or \ - general_settings.reimbursable_expenses_object == 'BILL'): - assert_valid('accounts_payable_name' in general_mapping and general_mapping['accounts_payable_name'], - 'account payable account name field is blank') - assert_valid('accounts_payable_id' in general_mapping and general_mapping['accounts_payable_id'], - 'account payable account id field is blank') - - if general_settings.employee_field_mapping == 'EMPLOYEE' and \ - (general_settings.reimbursable_expenses_object and general_settings.reimbursable_expenses_object != 'EXPENSE'): - assert_valid('bank_account_name' in general_mapping and general_mapping['bank_account_name'], - 'bank account name field is blank') - assert_valid('bank_account_id' in general_mapping and general_mapping['bank_account_id'], - 'bank account id field is blank') - - if general_settings.corporate_credit_card_expenses_object and \ - general_settings.corporate_credit_card_expenses_object not in ('BILL','DEBIT CARD EXPENSE'): - assert_valid('default_ccc_account_name' in general_mapping and general_mapping['default_ccc_account_name'], - 'default ccc account name field is blank') - assert_valid('default_ccc_account_id' in general_mapping and general_mapping['default_ccc_account_id'], - 'default ccc account id field is blank') - - if general_settings.corporate_credit_card_expenses_object == 'BILL': - assert_valid('default_ccc_vendor_name' in general_mapping and general_mapping['default_ccc_vendor_name'], - 'default ccc vendor name field is blank') - assert_valid('default_ccc_vendor_id' in general_mapping and general_mapping['default_ccc_vendor_id'], - 'default ccc vendor id field is blank') - - if general_settings.sync_fyle_to_qbo_payments: - assert_valid( - 'bill_payment_account_name' in general_mapping and general_mapping['bill_payment_account_name'], - 'bill payment account name field is blank') - assert_valid( - 'bill_payment_account_id' in general_mapping and general_mapping['bill_payment_account_id'], - 'bill payment account id field is blank') - - if general_settings.reimbursable_expenses_object == 'EXPENSE': - assert_valid('qbo_expense_account_name' in general_mapping and general_mapping['qbo_expense_account_name'], - 'qbo expense account name field is blank') - assert_valid('qbo_expense_account_id' in general_mapping and general_mapping['qbo_expense_account_id'], - 'qbo expense account id field is blank') - - if general_settings.corporate_credit_card_expenses_object == 'DEBIT CARD EXPENSE': - assert_valid('default_debit_card_account_name' in general_mapping and general_mapping['default_debit_card_account_name'], - 'debit card account name field is blank') - assert_valid('default_debit_card_account_id' in general_mapping and general_mapping['default_debit_card_account_id'], - 'debit card account id field is blank') - - general_mapping_object, _ = GeneralMapping.objects.update_or_create( - workspace_id=self.__workspace_id, - defaults=general_mapping - ) - - schedule_bill_payment_creation( - sync_fyle_to_qbo_payments=general_settings.sync_fyle_to_qbo_payments, - workspace_id=self.__workspace_id - ) - - schedule_auto_map_ccc_employees(self.__workspace_id) - return general_mapping_object diff --git a/apps/mappings/views.py b/apps/mappings/views.py index 22640ff0..8dc16e57 100644 --- a/apps/mappings/views.py +++ b/apps/mappings/views.py @@ -3,11 +3,7 @@ from rest_framework.response import Response from rest_framework.views import status -from fyle_qbo_api.utils import assert_valid - -from .serializers import GeneralMappingSerializer from .models import GeneralMapping -from .utils import MappingUtils from ..workspaces.models import WorkspaceGeneralSettings from apps.exceptions import handle_view_exceptions diff --git a/apps/quickbooks_online/queue.py b/apps/quickbooks_online/queue.py new file mode 100644 index 00000000..9a02e7d3 --- /dev/null +++ b/apps/quickbooks_online/queue.py @@ -0,0 +1,276 @@ +from datetime import datetime, timedelta +from typing import List + +from django_q.tasks import Chain, async_task +from django.db.models import Q +from django_q.models import Schedule + +from apps.tasks.models import TaskLog + +from apps.workspaces.models import FyleCredential, WorkspaceGeneralSettings +from apps.fyle.models import ExpenseGroup + +def async_run_post_configration_triggers(workspace_general_settings: WorkspaceGeneralSettings): + async_task( + 'apps.quickbooks_online.tasks.async_sync_accounts', + int(workspace_general_settings.workspace_id) + ) + + +def schedule_bills_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule bills creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, bill__id__isnull=True, exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_BILL' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_BILL' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_bill', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() + + +def schedule_cheques_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule cheque creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, cheque__id__isnull=True, exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_CHECK' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_CHECK' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_cheque', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() + + +def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule journal_entry creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, journalentry__id__isnull=True, + exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_JOURNAL_ENTRY' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_JOURNAL_ENTRY' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_journal_entry', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() + + +def schedule_credit_card_purchase_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule credit card purchase creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, creditcardpurchase__id__isnull=True, + exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_CREDIT_CARD_PURCHASE' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_CREDIT_CARD_PURCHASE' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_credit_card_purchase', expense_group, task_log.id, + last_export) + + if chain.length() > 1: + chain.run() + + +def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str]): + """ + Schedule QBO expense creation + :param expense_group_ids: List of expense group ids + :param workspace_id: workspace id + :return: None + """ + if expense_group_ids: + expense_groups = ExpenseGroup.objects.filter( + Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), + workspace_id=workspace_id, id__in=expense_group_ids, qboexpense__id__isnull=True, exported_at__isnull=True + ).all() + + chain = Chain() + + fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) + chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) + + for index, expense_group in enumerate(expense_groups): + task_log, _ = TaskLog.objects.get_or_create( + workspace_id=expense_group.workspace_id, + expense_group=expense_group, + defaults={ + 'status': 'ENQUEUED', + 'type': 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else + 'CREATING_DEBIT_CARD_EXPENSE' + } + ) + if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: + task_log.type = 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else \ + 'CREATING_DEBIT_CARD_EXPENSE' + task_log.status = 'ENQUEUED' + task_log.save() + + last_export = False + if expense_groups.count() == index + 1: + last_export = True + + chain.append('apps.quickbooks_online.tasks.create_qbo_expense', expense_group, task_log.id, last_export) + + if chain.length() > 1: + chain.run() + + +def schedule_qbo_objects_status_sync(sync_qbo_to_fyle_payments, workspace_id): + if sync_qbo_to_fyle_payments: + start_datetime = datetime.now() + schedule, _ = Schedule.objects.update_or_create( + func='apps.quickbooks_online.tasks.check_qbo_object_status', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.quickbooks_online.tasks.check_qbo_object_status', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() + + +def schedule_reimbursements_sync(sync_qbo_to_fyle_payments, workspace_id): + if sync_qbo_to_fyle_payments: + start_datetime = datetime.now() + timedelta(hours=12) + schedule, _ = Schedule.objects.update_or_create( + func='apps.quickbooks_online.tasks.process_reimbursements', + args='{}'.format(workspace_id), + defaults={ + 'schedule_type': Schedule.MINUTES, + 'minutes': 24 * 60, + 'next_run': start_datetime + } + ) + else: + schedule: Schedule = Schedule.objects.filter( + func='apps.quickbooks_online.tasks.process_reimbursements', + args='{}'.format(workspace_id) + ).first() + + if schedule: + schedule.delete() diff --git a/apps/workspaces/apis/advanced_configurations/triggers.py b/apps/workspaces/apis/advanced_configurations/triggers.py index e75dcaed..b92751e2 100644 --- a/apps/workspaces/apis/advanced_configurations/triggers.py +++ b/apps/workspaces/apis/advanced_configurations/triggers.py @@ -1,5 +1,5 @@ from apps.workspaces.models import WorkspaceGeneralSettings -from apps.workspaces.queue import schedule_qbo_objects_status_sync, schedule_reimbursements_sync +from apps.quickbooks_online.queue import schedule_qbo_objects_status_sync, schedule_reimbursements_sync from apps.mappings.queue import schedule_bill_payment_creation diff --git a/apps/workspaces/apis/export_settings/triggers.py b/apps/workspaces/apis/export_settings/triggers.py index 12c0f426..2645d877 100644 --- a/apps/workspaces/apis/export_settings/triggers.py +++ b/apps/workspaces/apis/export_settings/triggers.py @@ -1,7 +1,7 @@ from typing import Dict from apps.workspaces.models import WorkspaceGeneralSettings -from apps.workspaces.queue import async_disable_category_for_items_mapping +from apps.mappings.queue import async_disable_category_for_items_mapping class ExportSettingsTrigger: def __init__(self, workspace_general_settings: Dict, workspace_id: int): diff --git a/apps/workspaces/apis/import_settings/triggers.py b/apps/workspaces/apis/import_settings/triggers.py index dcb00046..a9dd8c07 100644 --- a/apps/workspaces/apis/import_settings/triggers.py +++ b/apps/workspaces/apis/import_settings/triggers.py @@ -8,8 +8,8 @@ from apps.fyle.models import ExpenseGroupSettings from apps.mappings.helpers import schedule_or_delete_fyle_import_tasks from apps.workspaces.models import WorkspaceGeneralSettings -from apps.workspaces.queue import schedule_tax_groups_creation, async_disable_category_for_items_mapping -from apps.mappings.queue import schedule_cost_centers_creation, schedule_fyle_attributes_creation +from apps.mappings.queue import (schedule_cost_centers_creation, schedule_fyle_attributes_creation, + schedule_tax_groups_creation, async_disable_category_for_items_mapping) class ImportSettingsTrigger: """ diff --git a/apps/workspaces/apis/map_employees/triggers.py b/apps/workspaces/apis/map_employees/triggers.py index 11c549fa..0967a7c5 100644 --- a/apps/workspaces/apis/map_employees/triggers.py +++ b/apps/workspaces/apis/map_employees/triggers.py @@ -1,4 +1,4 @@ -from apps.workspaces.queue import schedule_auto_map_employees +from apps.mappings.queue import schedule_auto_map_employees from apps.workspaces.models import WorkspaceGeneralSettings diff --git a/apps/workspaces/queue.py b/apps/workspaces/queue.py index 5ce57dce..407d114b 100644 --- a/apps/workspaces/queue.py +++ b/apps/workspaces/queue.py @@ -1,23 +1,7 @@ from datetime import datetime, timedelta -from typing import List -from django_q.tasks import Chain, async_task -from django.db.models import Q from django_q.models import Schedule -from apps.tasks.models import TaskLog - -from apps.workspaces.models import FyleCredential, WorkspaceGeneralSettings -from apps.fyle.models import ExpenseGroup - -def async_run_post_configration_triggers(instance:WorkspaceGeneralSettings): - async_task( - 'apps.quickbooks_online.tasks.async_sync_accounts', - int(instance.workspace_id) - ) - -def async_disable_category_for_items_mapping(workspace_id: int): - async_task('apps.mappings.tasks.disable_category_for_items_mapping', workspace_id) def schedule_email_notification(workspace_id: int, schedule_enabled: bool, hours: int): if schedule_enabled: @@ -37,307 +21,4 @@ def schedule_email_notification(workspace_id: int, schedule_enabled: bool, hours ).first() if schedule: - schedule.delete() - - -def schedule_bills_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule bills creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, bill__id__isnull=True, exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_BILL' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_BILL' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_bill', expense_group, task_log.id, last_export) - - if chain.length() > 1: - chain.run() - - -def schedule_cheques_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule cheque creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, cheque__id__isnull=True, exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_CHECK' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_CHECK' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_cheque', expense_group, task_log.id, last_export) - - if chain.length() > 1: - chain.run() - - -def schedule_journal_entry_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule journal_entry creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, journalentry__id__isnull=True, - exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_JOURNAL_ENTRY' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_JOURNAL_ENTRY' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_journal_entry', expense_group, task_log.id, last_export) - - if chain.length() > 1: - chain.run() - - -def schedule_credit_card_purchase_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule credit card purchase creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, creditcardpurchase__id__isnull=True, - exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_CREDIT_CARD_PURCHASE' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_CREDIT_CARD_PURCHASE' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_credit_card_purchase', expense_group, task_log.id, - last_export) - - if chain.length() > 1: - chain.run() - - -def schedule_qbo_expense_creation(workspace_id: int, expense_group_ids: List[str]): - """ - Schedule QBO expense creation - :param expense_group_ids: List of expense group ids - :param workspace_id: workspace id - :return: None - """ - if expense_group_ids: - expense_groups = ExpenseGroup.objects.filter( - Q(tasklog__id__isnull=True) | ~Q(tasklog__status__in=['IN_PROGRESS', 'COMPLETE']), - workspace_id=workspace_id, id__in=expense_group_ids, qboexpense__id__isnull=True, exported_at__isnull=True - ).all() - - chain = Chain() - - fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) - chain.append('apps.fyle.tasks.sync_dimensions', fyle_credentials) - - for index, expense_group in enumerate(expense_groups): - task_log, _ = TaskLog.objects.get_or_create( - workspace_id=expense_group.workspace_id, - expense_group=expense_group, - defaults={ - 'status': 'ENQUEUED', - 'type': 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else - 'CREATING_DEBIT_CARD_EXPENSE' - } - ) - if task_log.status not in ['IN_PROGRESS', 'ENQUEUED']: - task_log.type = 'CREATING_EXPENSE' if expense_group.fund_source == 'PERSONAL' else \ - 'CREATING_DEBIT_CARD_EXPENSE' - task_log.status = 'ENQUEUED' - task_log.save() - - last_export = False - if expense_groups.count() == index + 1: - last_export = True - - chain.append('apps.quickbooks_online.tasks.create_qbo_expense', expense_group, task_log.id, last_export) - - if chain.length() > 1: - chain.run() - - -def schedule_qbo_objects_status_sync(sync_qbo_to_fyle_payments, workspace_id): - if sync_qbo_to_fyle_payments: - start_datetime = datetime.now() - schedule, _ = Schedule.objects.update_or_create( - func='apps.quickbooks_online.tasks.check_qbo_object_status', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.quickbooks_online.tasks.check_qbo_object_status', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - -def schedule_reimbursements_sync(sync_qbo_to_fyle_payments, workspace_id): - if sync_qbo_to_fyle_payments: - start_datetime = datetime.now() + timedelta(hours=12) - schedule, _ = Schedule.objects.update_or_create( - func='apps.quickbooks_online.tasks.process_reimbursements', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.quickbooks_online.tasks.process_reimbursements', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() - - -def schedule_tax_groups_creation(import_tax_codes, workspace_id): - if import_tax_codes: - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.auto_create_tax_codes_mappings', - args='{}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': datetime.now() - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.auto_create_tax_codes_mappings', - args='{}'.format(workspace_id), - ).first() - - if schedule: - schedule.delete() - - -def schedule_auto_map_employees(employee_mapping_preference: str, workspace_id: int): - if employee_mapping_preference: - start_datetime = datetime.now() - - schedule, _ = Schedule.objects.update_or_create( - func='apps.mappings.tasks.async_auto_map_employees', - args='{0}'.format(workspace_id), - defaults={ - 'schedule_type': Schedule.MINUTES, - 'minutes': 24 * 60, - 'next_run': start_datetime - } - ) - else: - schedule: Schedule = Schedule.objects.filter( - func='apps.mappings.tasks.async_auto_map_employees', - args='{}'.format(workspace_id) - ).first() - - if schedule: - schedule.delete() + schedule.delete() \ No newline at end of file diff --git a/apps/workspaces/signals.py b/apps/workspaces/signals.py index 6b2d594f..6fbc349b 100644 --- a/apps/workspaces/signals.py +++ b/apps/workspaces/signals.py @@ -8,7 +8,7 @@ from apps.workspaces.models import Workspace, WorkspaceGeneralSettings from apps.workspaces.utils import delete_cards_mapping_settings -from .queue import async_run_post_configration_triggers +from apps.quickbooks_online.queue import async_run_post_configration_triggers @receiver(post_save, sender=WorkspaceGeneralSettings) def run_post_configration_triggers(sender, instance: WorkspaceGeneralSettings, **kwargs): diff --git a/apps/workspaces/tasks.py b/apps/workspaces/tasks.py index 091a1aef..b97378af 100644 --- a/apps/workspaces/tasks.py +++ b/apps/workspaces/tasks.py @@ -17,9 +17,10 @@ from apps.tasks.models import TaskLog from fyle_accounting_mappings.models import ExpenseAttribute from apps.tasks.models import Error - -from .queue import (schedule_email_notification, schedule_bills_creation, schedule_cheques_creation, +from apps.quickbooks_online.queue import (schedule_bills_creation, schedule_cheques_creation, schedule_journal_entry_creation, schedule_credit_card_purchase_creation, schedule_qbo_expense_creation) +from .queue import schedule_email_notification + logger = logging.getLogger(__name__) logger.level = logging.INFO diff --git a/apps/workspaces/utils.py b/apps/workspaces/utils.py index 3fed3a0b..431716f9 100644 --- a/apps/workspaces/utils.py +++ b/apps/workspaces/utils.py @@ -14,9 +14,9 @@ from fyle_qbo_api.utils import assert_valid from .models import WorkspaceGeneralSettings from ..fyle.models import ExpenseGroupSettings -from .queue import (schedule_tax_groups_creation, schedule_auto_map_employees, schedule_qbo_objects_status_sync, - schedule_reimbursements_sync) -from apps.mappings.queue import schedule_auto_map_ccc_employees, schedule_bill_payment_creation +from apps.quickbooks_online.queue import schedule_qbo_objects_status_sync, schedule_reimbursements_sync +from apps.mappings.queue import (schedule_auto_map_ccc_employees, schedule_bill_payment_creation, + schedule_tax_groups_creation, schedule_auto_map_employees) def generate_qbo_refresh_token(authorization_code: str, redirect_uri: str) -> str: """ diff --git a/tests/test_quickbooks_online/test_tasks.py b/tests/test_quickbooks_online/test_tasks.py index eae58383..560a9ddd 100644 --- a/tests/test_quickbooks_online/test_tasks.py +++ b/tests/test_quickbooks_online/test_tasks.py @@ -12,6 +12,7 @@ from apps.quickbooks_online.tasks import * from apps.workspaces.queue import * from apps.mappings.queue import * +from apps.quickbooks_online.queue import * from fyle_qbo_api.exceptions import BulkError from qbosdk.exceptions import WrongParamsError from fyle_accounting_mappings.models import EmployeeMapping