Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Job, Dep Field code-prepending support #206

Merged
merged 13 commits into from
Jul 23, 2024
28 changes: 28 additions & 0 deletions apps/mappings/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from datetime import datetime, timedelta, timezone
from apps.mappings.models import ImportLog


def format_attribute_name(use_code_in_naming: bool, attribute_name: str, attribute_code: str = None) -> str:
Hrishabh17 marked this conversation as resolved.
Show resolved Hide resolved
"""
Format the attribute name based on the use_code_in_naming flag
"""
if use_code_in_naming and attribute_code:
return "{} {}".format(attribute_code, attribute_name)
return attribute_name


def is_job_sync_allowed(import_log: ImportLog = None) -> bool:
"""
Check if job sync is allowed
"""
time_difference = datetime.now(timezone.utc) - timedelta(minutes=30)

if (
not import_log
or import_log.status != 'COMPLETE'
Hrishabh17 marked this conversation as resolved.
Show resolved Hide resolved
or import_log.last_successful_run_at is None
or import_log.last_successful_run_at < time_difference
):
return True

return False
10 changes: 8 additions & 2 deletions apps/mappings/imports/modules/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from apps.sage300.utils import SageDesktopConnector
from apps.mappings.exceptions import handle_import_exceptions
from apps.accounting_exports.models import Error

from apps.mappings.helpers import format_attribute_name

logger = logging.getLogger(__name__)
logger.level = logging.INFO
Expand All @@ -36,12 +36,14 @@ def __init__(
destination_field: str,
platform_class_name: str,
sync_after:datetime,
use_code_in_naming: bool = False
):
self.workspace_id = workspace_id
self.source_field = source_field
self.destination_field = destination_field
self.platform_class_name = platform_class_name
self.sync_after = sync_after
self.use_code_in_naming = use_code_in_naming

def get_platform_class(self, platform: PlatformConnector):
"""
Expand Down Expand Up @@ -92,7 +94,11 @@ def remove_duplicate_attributes(self, destination_attributes: List[DestinationAt
attribute_values = []

for destination_attribute in destination_attributes:
if destination_attribute.value.lower() not in attribute_values:
attribute_value = destination_attribute.value
attribute_value = format_attribute_name(self.use_code_in_naming, destination_attribute.value, destination_attribute.code)

if attribute_value.lower() not in attribute_values:
destination_attribute.value = attribute_value
unique_attributes.append(destination_attribute)
attribute_values.append(destination_attribute.value.lower())
Hrishabh17 marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
3 changes: 2 additions & 1 deletion apps/mappings/imports/modules/categories.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ class Category(Base):
Class for Category module
"""

def __init__(self, workspace_id: int, destination_field: str, sync_after: datetime):
def __init__(self, workspace_id: int, destination_field: str, sync_after: datetime, use_code_in_naming: bool = False):
super().__init__(
workspace_id=workspace_id,
source_field="CATEGORY",
destination_field=destination_field,
platform_class_name="categories",
sync_after=sync_after,
use_code_in_naming=use_code_in_naming
)

def trigger_import(self):
Expand Down
3 changes: 2 additions & 1 deletion apps/mappings/imports/modules/cost_centers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ class CostCenter(Base):
Class for Cost Center module
"""

def __init__(self, workspace_id: int, destination_field: str, sync_after: datetime):
def __init__(self, workspace_id: int, destination_field: str, sync_after: datetime, use_code_in_naming: bool = False):
super().__init__(
workspace_id=workspace_id,
source_field="COST_CENTER",
destination_field=destination_field,
platform_class_name="cost_centers",
sync_after=sync_after,
use_code_in_naming=use_code_in_naming
)

def trigger_import(self):
Expand Down
5 changes: 3 additions & 2 deletions apps/mappings/imports/modules/expense_custom_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ class ExpenseCustomField(Base):
"""
Class for ExepenseCustomField module
"""
def __init__(self, workspace_id: int, source_field: str, destination_field: str, sync_after: datetime):
def __init__(self, workspace_id: int, source_field: str, destination_field: str, sync_after: datetime, use_code_in_naming: bool = False):
super().__init__(
workspace_id=workspace_id,
source_field=source_field,
destination_field=destination_field,
platform_class_name='expense_custom_fields',
sync_after=sync_after
sync_after=sync_after,
use_code_in_naming=use_code_in_naming
)

def trigger_import(self):
Expand Down
5 changes: 3 additions & 2 deletions apps/mappings/imports/modules/merchants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ class Merchant(Base):
"""
Class for Merchant module
"""
def __init__(self, workspace_id: int, destination_field: str, sync_after: datetime):
def __init__(self, workspace_id: int, destination_field: str, sync_after: datetime, use_code_in_naming: bool = False):
super().__init__(
workspace_id=workspace_id,
source_field='MERCHANT',
destination_field=destination_field,
platform_class_name='merchants',
sync_after=sync_after
sync_after=sync_after,
use_code_in_naming=use_code_in_naming
)

def trigger_import(self):
Expand Down
3 changes: 2 additions & 1 deletion apps/mappings/imports/modules/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ class Project(Base):
Class for Project module
"""

def __init__(self, workspace_id: int, destination_field: str, sync_after: datetime):
def __init__(self, workspace_id: int, destination_field: str, sync_after: datetime, use_code_in_naming: bool = False):
super().__init__(
workspace_id=workspace_id,
source_field="PROJECT",
destination_field=destination_field,
platform_class_name="projects",
sync_after=sync_after,
use_code_in_naming=use_code_in_naming
)

def trigger_import(self):
Expand Down
30 changes: 24 additions & 6 deletions apps/mappings/imports/queues.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from apps.workspaces.models import ImportSetting
from apps.fyle.models import DependentFieldSetting
from apps.mappings.models import ImportLog
from apps.mappings.helpers import is_job_sync_allowed


def chain_import_fields_to_fyle(workspace_id):
Expand All @@ -11,14 +12,28 @@ def chain_import_fields_to_fyle(workspace_id):
: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)
dependent_field_settings = DependentFieldSetting.objects.filter(workspace_id=workspace_id, is_import_enabled=True).first()
project_mapping = MappingSetting.objects.filter(workspace_id=workspace_id, source_field='PROJECT', import_to_fyle=True).first()

import_code_fields = import_settings.import_code_fields
project_import_log = ImportLog.objects.filter(workspace_id=workspace_id, attribute_type='PROJECT').first()

# We'll only sync job when the time_difference > 30 minutes to avoid
# any dependent field import issue due to timestamp on job name update
is_sync_allowed = is_job_sync_allowed(project_import_log)

custom_field_mapping_settings = []
project_mapping = None

for setting in mapping_settings:
if setting.is_custom:
custom_field_mapping_settings.append(setting)
if setting.source_field == 'PROJECT':
project_mapping = setting

chain = Chain()

if project_mapping and dependent_field_settings:
if project_mapping and dependent_field_settings and is_sync_allowed:
cost_code_import_log = ImportLog.create('COST_CODE', workspace_id)
cost_category_import_log = ImportLog.create('COST_CATEGORY', workspace_id)
chain.append('apps.mappings.tasks.sync_sage300_attributes', 'JOB', workspace_id)
Expand Down Expand Up @@ -47,7 +62,9 @@ def chain_import_fields_to_fyle(workspace_id):
'apps.mappings.imports.tasks.trigger_import_via_schedule',
workspace_id,
mapping_setting.destination_field,
mapping_setting.source_field
mapping_setting.source_field,
False,
True if mapping_setting.destination_field in import_code_fields else False
)

for custom_fields_mapping_setting in custom_field_mapping_settings:
Expand All @@ -56,10 +73,11 @@ def chain_import_fields_to_fyle(workspace_id):
workspace_id,
custom_fields_mapping_setting.destination_field,
custom_fields_mapping_setting.source_field,
True
True,
True if custom_fields_mapping_setting.destination_field in import_code_fields else False
)

if project_mapping and dependent_field_settings:
if project_mapping and dependent_field_settings and is_sync_allowed:
chain.append('apps.sage300.dependent_fields.import_dependent_fields_to_fyle', workspace_id)

if chain.length() > 0:
Expand Down
12 changes: 9 additions & 3 deletions apps/mappings/imports/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@
}


def trigger_import_via_schedule(workspace_id: int, destination_field: str, source_field: str, is_custom: bool = False):
def trigger_import_via_schedule(
workspace_id: int,
destination_field: str,
source_field: str,
is_custom: bool = False,
use_code_in_naming: bool = False
):
"""
Trigger import via schedule
:param workspace_id: Workspace id
Expand All @@ -30,9 +36,9 @@ def trigger_import_via_schedule(workspace_id: int, destination_field: str, sourc
sync_after = import_log.last_successful_run_at if import_log else None

if is_custom:
item = ExpenseCustomField(workspace_id, source_field, destination_field, sync_after)
item = ExpenseCustomField(workspace_id, source_field, destination_field, sync_after, use_code_in_naming)
item.trigger_import()
else:
module_class = SOURCE_FIELD_CLASS_MAP[source_field]
item = module_class(workspace_id, destination_field, sync_after)
item = module_class(workspace_id, destination_field, sync_after, use_code_in_naming)
item.trigger_import()
Loading
Loading