-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
956b860
commit 84f437a
Showing
12 changed files
with
306 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from django_q.tasks import Chain | ||
from fyle_accounting_mappings.models import MappingSetting | ||
from apps.workspaces.models import ImportSetting | ||
|
||
|
||
def chain_import_fields_to_fyle(workspace_id): | ||
""" | ||
Chain import fields to Fyle | ||
:param workspace_id: Workspace Id | ||
""" | ||
mapping_settings = MappingSetting.objects.filter(workspace_id=workspace_id, import_to_fyle=True) | ||
custom_field_mapping_settings = MappingSetting.objects.filter(workspace_id=workspace_id, is_custom=True, import_to_fyle=True) | ||
import_settings = ImportSetting.objects.get(workspace_id=workspace_id) | ||
chain = Chain() | ||
|
||
if import_settings.import_categories: | ||
chain.append( | ||
'apps.mappings.imports.tasks.trigger_import_via_schedule', | ||
workspace_id, | ||
'ACCOUNT', | ||
'CATEGORY' | ||
) | ||
|
||
for mapping_setting in mapping_settings: | ||
if mapping_setting.source_field in ['PROJECT', 'COST_CENTER']: | ||
chain.append( | ||
'apps.mappings.imports.tasks.trigger_import_via_schedule', | ||
workspace_id, | ||
mapping_setting.destination_field, | ||
mapping_setting.source_field | ||
) | ||
|
||
for custom_fields_mapping_setting in custom_field_mapping_settings: | ||
chain.append( | ||
'apps.mappings.imports.tasks.trigger_import_via_schedule', | ||
workspace_id, | ||
custom_fields_mapping_setting.destination_field, | ||
custom_fields_mapping_setting.source_field, | ||
True | ||
) | ||
|
||
if chain.length() > 0: | ||
chain.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
from datetime import datetime | ||
from django_q.models import Schedule | ||
from fyle_accounting_mappings.models import MappingSetting | ||
|
||
from apps.fyle.models import DependentFieldSetting | ||
from apps.workspaces.models import ImportSetting | ||
|
||
|
||
def schedule_or_delete_dependent_field_tasks(import_settings: ImportSetting): | ||
""" | ||
:param configuration: Workspace Configuration Instance | ||
:return: None | ||
""" | ||
project_mapping = MappingSetting.objects.filter( | ||
source_field='PROJECT', | ||
workspace_id=import_settings.workspace_id, | ||
import_to_fyle=True | ||
).first() | ||
dependent_fields = DependentFieldSetting.objects.filter(workspace_id=import_settings.workspace_id, is_import_enabled=True).first() | ||
|
||
if project_mapping and dependent_fields: | ||
start_datetime = datetime.now() | ||
Schedule.objects.update_or_create( | ||
func='apps.mappings.tasks.auto_import_and_map_fyle_fields', | ||
args='{}'.format(import_settings.workspace_id), | ||
defaults={ | ||
'schedule_type': Schedule.MINUTES, | ||
'minutes': 24 * 60, | ||
'next_run': start_datetime | ||
} | ||
) | ||
elif not (project_mapping and dependent_fields): | ||
Schedule.objects.filter( | ||
func='apps.mappings.tasks.auto_import_and_map_fyle_fields', | ||
args='{}'.format(import_settings.workspace_id) | ||
).delete() | ||
|
||
|
||
def schedule_or_delete_fyle_import_tasks(import_settings: ImportSetting, mapping_setting_instance: MappingSetting = None): | ||
""" | ||
Schedule or delete Fyle import tasks based on the import settingss. | ||
:param import_settingss: Workspace ImportSetting Instance | ||
:param instance: Mapping Setting Instance | ||
:return: None | ||
""" | ||
task_to_be_scheduled = None | ||
# Check if there is a task to be scheduled | ||
if mapping_setting_instance and mapping_setting_instance.import_to_fyle: | ||
task_to_be_scheduled = mapping_setting_instance | ||
|
||
if task_to_be_scheduled or import_settings.import_categories: | ||
Schedule.objects.update_or_create( | ||
func='apps.mappings.imports.queues.chain_import_fields_to_fyle', | ||
args='{}'.format(import_settings.workspace_id), | ||
defaults={ | ||
'schedule_type': Schedule.MINUTES, | ||
'minutes': 24 * 60, | ||
'next_run': datetime.now() | ||
} | ||
) | ||
return | ||
|
||
import_fields_count = MappingSetting.objects.filter( | ||
import_to_fyle=True, | ||
workspace_id=import_settings.workspace_id, | ||
source_field__in=['CATEGORY', 'PROJECT', 'COST_CENTER'] | ||
).count() | ||
|
||
custom_field_import_fields_count = MappingSetting.objects.filter( | ||
import_to_fyle=True, | ||
workspace_id=import_settings.workspace_id, | ||
is_custom=True | ||
).count() | ||
|
||
# If the import fields count is 0, delete the schedule | ||
if import_fields_count == 0 and custom_field_import_fields_count == 0: | ||
Schedule.objects.filter( | ||
func='apps.mappings.imports.queues.chain_import_fields_to_fyle', | ||
args='{}'.format(import_settings.workspace_id) | ||
).delete() | ||
|
||
# Schedule or delete dependent field tasks | ||
schedule_or_delete_dependent_field_tasks(import_settings=import_settings) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import logging | ||
from datetime import timedelta, datetime, timezone | ||
from django.db.models.signals import post_save, pre_save | ||
from django.dispatch import receiver | ||
|
||
from rest_framework.exceptions import ValidationError | ||
from fyle_accounting_mappings.models import MappingSetting | ||
from fyle_integrations_platform_connector import PlatformConnector | ||
from fyle.platform.exceptions import WrongParamsError | ||
|
||
from apps.mappings.imports.schedules import schedule_or_delete_fyle_import_tasks | ||
from apps.workspaces.models import ImportSetting | ||
from apps.mappings.models import ImportLog | ||
from apps.workspaces.models import FyleCredential | ||
from apps.mappings.imports.modules.expense_custom_fields import ExpenseCustomField | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
@receiver(post_save, sender=MappingSetting) | ||
def run_post_mapping_settings_triggers(sender, instance: MappingSetting, **kwargs): | ||
""" | ||
:param sender: Sender Class | ||
:param instance: Row instance of Sender Class | ||
:return: None | ||
""" | ||
import_settings = ImportSetting.objects.filter(workspace_id=instance.workspace_id).first() | ||
|
||
if instance.source_field == 'PROJECT': | ||
schedule_or_delete_fyle_import_tasks(import_settings, instance) | ||
|
||
if instance.source_field == 'COST_CENTER': | ||
schedule_or_delete_fyle_import_tasks(import_settings, instance) | ||
|
||
if instance.is_custom: | ||
schedule_or_delete_fyle_import_tasks(import_settings, instance) | ||
|
||
|
||
@receiver(pre_save, sender=MappingSetting) | ||
def run_pre_mapping_settings_triggers(sender, instance: MappingSetting, **kwargs): | ||
""" | ||
:param sender: Sender Class | ||
:param instance: Row instance of Sender Class | ||
:return: None | ||
""" | ||
default_attributes = ['EMPLOYEE', 'CATEGORY', 'PROJECT', 'COST_CENTER'] | ||
|
||
instance.source_field = instance.source_field.upper().replace(' ', '_') | ||
|
||
if instance.source_field not in default_attributes and instance.import_to_fyle: | ||
# TODO: sync intacct fields before we upload custom field | ||
try: | ||
workspace_id = int(instance.workspace_id) | ||
# Checking is import_log exists or not if not create one | ||
import_log, is_created = ImportLog.objects.get_or_create( | ||
workspace_id=workspace_id, | ||
attribute_type=instance.source_field, | ||
defaults={ | ||
'status': 'IN_PROGRESS' | ||
} | ||
) | ||
|
||
last_successful_run_at = None | ||
if import_log and not is_created: | ||
last_successful_run_at = import_log.last_successful_run_at if import_log.last_successful_run_at else None | ||
time_difference = datetime.now() - timedelta(minutes=32) | ||
offset_aware_time_difference = time_difference.replace(tzinfo=timezone.utc) | ||
|
||
# if the import_log is present and the last_successful_run_at is less than 30mins then we need to update it | ||
# so that the schedule can run | ||
if last_successful_run_at and offset_aware_time_difference\ | ||
and (offset_aware_time_difference < last_successful_run_at): | ||
import_log.last_successful_run_at = offset_aware_time_difference | ||
last_successful_run_at = offset_aware_time_difference | ||
import_log.save() | ||
|
||
# Creating the expense_custom_field object with the correct last_successful_run_at value | ||
expense_custom_field = ExpenseCustomField( | ||
workspace_id=workspace_id, | ||
source_field=instance.source_field, | ||
destination_field=instance.destination_field, | ||
sync_after=last_successful_run_at | ||
) | ||
|
||
fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) | ||
platform = PlatformConnector(fyle_credentials=fyle_credentials) | ||
|
||
# setting the import_log status to IN_PROGRESS | ||
import_log.status = 'IN_PROGRESS' | ||
import_log.save() | ||
|
||
expense_custom_field.construct_payload_and_import_to_fyle(platform, import_log) | ||
expense_custom_field.sync_expense_attributes(platform) | ||
|
||
# NOTE: We are not setting the import_log status to COMPLETE | ||
# since the post_save trigger will run the import again in async manner | ||
|
||
except WrongParamsError as error: | ||
logger.error( | ||
'Error while creating %s workspace_id - %s in Fyle %s %s', | ||
instance.source_field, instance.workspace_id, error.message, {'error': error.response} | ||
) | ||
if error.response and 'message' in error.response: | ||
raise ValidationError({ | ||
'message': error.response['message'], | ||
'field_name': instance.source_field | ||
}) | ||
|
||
# setting the import_log.last_successful_run_at to -30mins for the post_save_trigger | ||
import_log = ImportLog.objects.filter(workspace_id=workspace_id, attribute_type=instance.source_field).first() | ||
if import_log.last_successful_run_at: | ||
last_successful_run_at = import_log.last_successful_run_at - timedelta(minutes=30) | ||
import_log.last_successful_run_at = last_successful_run_at | ||
import_log.save() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
"""fyle_intacct_api URL Configuration | ||
The `urlpatterns` list routes URLs to views. For more information please see: | ||
https://docs.djangoproject.com/en/3.0/topics/http/urls/ | ||
Examples: | ||
Function views | ||
1. Add an import: from my_app import views | ||
2. Add a URL to urlpatterns: path('', views.home, name='home') | ||
Class-based views | ||
1. Add an import: from other_app.views import Home | ||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') | ||
Including another URLconf | ||
1. Import the include() function: from django.urls import include, path | ||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) | ||
""" | ||
from django.urls import path, include | ||
|
||
urlpatterns = [ | ||
path('', include('fyle_accounting_mappings.urls')) | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.