Skip to content

Commit

Permalink
Import Jobs as Projects (#58)
Browse files Browse the repository at this point in the history
* auto sync chart of accounts as categories

* base pr

* Import Jobs as Projects

* Test cases added

* Flake 8 resolved

* migration change

* Error resolved

* Test cases resolved

* comets resolved

* Flake8 resolve

* Comments resolved

---------

Co-authored-by: Nilesh Pant <[email protected]>
  • Loading branch information
ruuushhh and NileshPant1999 authored Nov 2, 2023
1 parent ca230e9 commit 956b860
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 8 deletions.
11 changes: 11 additions & 0 deletions apps/mappings/imports/modules/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ def get_platform_class(self, platform: PlatformConnector):
"""
return getattr(platform, self.platform_class_name)

def get_auto_sync_permission(self):
"""
Get the auto sync permission
:return: bool
"""
is_auto_sync_status_allowed = False
if (self.destination_field == 'PROJECT' and self.source_field == 'PROJECT') or self.source_field == 'CATEGORY':
is_auto_sync_status_allowed = True

return is_auto_sync_status_allowed

def construct_attributes_filter(self, attribute_type: str, paginated_destination_attribute_values: List[str] = []):
"""
Construct the attributes filter
Expand Down
11 changes: 6 additions & 5 deletions apps/mappings/imports/modules/categories.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ def trigger_import(self):
def construct_fyle_payload(
self,
paginated_destination_attributes: List[DestinationAttribute],
existing_fyle_attributes_map: object
existing_fyle_attributes_map: object,
is_auto_sync_status_allowed: bool
):
"""
Construct Fyle payload for Category module
:param paginated_destination_attributes: List of paginated destination attributes
:param existing_fyle_attributes_map: Existing Fyle attributes map
:param is_auto_sync_status_allowed: Is auto sync status allowed
:return: Fyle payload
"""
payload = []
Expand All @@ -47,10 +49,9 @@ def construct_fyle_payload(
# Create a new category if it does not exist in Fyle
if attribute.value.lower() not in existing_fyle_attributes_map:
payload.append(category)
# Disable the existing category in Fyle if auto-sync status is
# allowed and the destination_attributes is inactive
elif not attribute.active:
category["id"] = existing_fyle_attributes_map[attribute.value.lower()]
# Disable the existing category in Fyle if auto-sync status is allowed and the destination_attributes is inactive
elif is_auto_sync_status_allowed and not attribute.active:
category['id'] = existing_fyle_attributes_map[attribute.value.lower()]
payload.append(category)

return payload
Expand Down
61 changes: 61 additions & 0 deletions apps/mappings/imports/modules/projects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from datetime import datetime
from typing import List
from apps.mappings.imports.modules.base import Base
from fyle_accounting_mappings.models import DestinationAttribute


class Project(Base):
"""
Class for Project module
"""

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

def trigger_import(self):
"""
Trigger import for Project module
"""
self.check_import_log_and_start_import()

def construct_fyle_payload(
self,
paginated_destination_attributes: List[DestinationAttribute],
existing_fyle_attributes_map: object,
is_auto_sync_status_allowed: bool
):
"""
Construct Fyle payload for Project module
:param paginated_destination_attributes: List of paginated destination attributes
:param existing_fyle_attributes_map: Existing Fyle attributes map
:param is_auto_sync_status_allowed: Is auto sync status allowed
:return: Fyle payload
"""
payload = []

for attribute in paginated_destination_attributes:
project = {
'name': attribute.value,
'code': attribute.destination_id,
'description': 'Sage 300 Project - {0}, Id - {1}'.format(
attribute.value,
attribute.destination_id
),
'is_enabled': True if attribute.active is None else attribute.active
}

# Create a new project if it does not exist in Fyle
if attribute.value.lower() not in existing_fyle_attributes_map:
payload.append(project)
# Disable the existing project in Fyle if auto-sync status is allowed and the destination_attributes is inactive
elif is_auto_sync_status_allowed and not attribute.active:
project['id'] = existing_fyle_attributes_map[attribute.value.lower()]
payload.append(project)

return payload
2 changes: 2 additions & 0 deletions apps/mappings/imports/tasks.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from apps.mappings.models import ImportLog
from apps.mappings.imports.modules.categories import Category
from apps.mappings.imports.modules.projects import Project
from apps.mappings.imports.modules.expense_custom_fields import ExpenseCustomField


SOURCE_FIELD_CLASS_MAP = {
'CATEGORY': Category,
'PROJECT': Project
}


Expand Down
20 changes: 20 additions & 0 deletions apps/mappings/migrations/0002_alter_importlog_workspace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.1.2 on 2023-11-02 09:05

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('workspaces', '0002_sage300credential_importsetting_fylecredential_and_more'),
('mappings', '0001_initial'),
]

operations = [
migrations.AlterField(
model_name='importlog',
name='workspace',
field=models.ForeignKey(help_text='Reference to Workspace model', on_delete=django.db.models.deletion.PROTECT, to='workspaces.workspace'),
),
]
4 changes: 2 additions & 2 deletions apps/mappings/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.db import models

from apps.workspaces.models import BaseModel
from apps.workspaces.models import BaseForeignWorkspaceModel
from sage_desktop_api.models.fields import (
CustomJsonField,
StringNotNullField,
Expand All @@ -18,7 +18,7 @@
)


class ImportLog(BaseModel):
class ImportLog(BaseForeignWorkspaceModel):
"""
Table to store import logs
"""
Expand Down
2 changes: 1 addition & 1 deletion apps/sage300/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from apps.workspaces.models import Workspace, Sage300Credential
from apps.sage300.helpers import sync_dimensions, check_interval_and_sync_dimension


logger = logging.getLogger(__name__)
logger.level = logging.INFO

Expand Down Expand Up @@ -79,6 +78,7 @@ class Sage300FieldSerializer(serializers.Serializer):
display_name = serializers.CharField()

def format_sage300_fields(self, workspace_id):

attribute_types = [
"VENDOR",
"ACCOUNT",
Expand Down
31 changes: 31 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from rest_framework.test import APIClient
from fyle.platform.platform import Platform
from fyle_rest_auth.models import User, AuthToken
from fyle_accounting_mappings.models import DestinationAttribute

from apps.fyle.helpers import get_access_token
from apps.workspaces.models import (
Expand Down Expand Up @@ -275,3 +276,33 @@ def add_accounting_export_summary():
successful_accounting_export_count = 5,
failed_accounting_export_count = 5
)


@pytest.fixture()
@pytest.mark.django_db(databases=['default'])
def add_project_mappings():
"""
Pytest fixtue to add project mappings to a workspace
"""
workspace_ids = [
1, 2, 3
]
for workspace_id in workspace_ids:
DestinationAttribute.objects.create(
workspace_id=workspace_id,
attribute_type='PROJECT',
display_name='Direct Mail Campaign',
value='Direct Mail Campaign',
destination_id='10064',
detail='Sage 300 Project - Direct Mail Campaign, Id - 10064',
active=True
)
DestinationAttribute.objects.create(
workspace_id=workspace_id,
attribute_type='PROJECT',
display_name='Platform APIs',
value='Platform APIs',
destination_id='10081',
detail='Sage 300 Project - Platform APIs, Id - 10081',
active=True
)
Empty file added tests/test_mappings/__init__.py
Empty file.
Empty file.
33 changes: 33 additions & 0 deletions tests/test_mappings/test_imports/test_modules/fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
data = {
"create_fyle_project_payload_create_new_case":
[
{
'name':'Direct Mail Campaign',
'code':'10064',
'description':'Sage 300 Project - Direct Mail Campaign, Id - 10064',
'is_enabled':True
},
{
'name':'Platform APIs',
'code':'10081',
'description':'Sage 300 Project - Platform APIs, Id - 10081',
'is_enabled':True
}

],
"create_fyle_project_payload_create_disable_case":
[
{
'code': '10064',
'description': 'Sage 300 Project - Direct Mail Campaign, Id - 10064',
'is_enabled': True,
'name': 'Direct Mail Campaign'
},
{
'code': '10081',
'description': 'Sage 300 Project - Platform APIs, Id - 10081',
'is_enabled': False,
'name': 'Platform APIs'
}
]
}
42 changes: 42 additions & 0 deletions tests/test_mappings/test_imports/test_modules/test_projects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from apps.mappings.imports.modules.projects import Project
from fyle_accounting_mappings.models import DestinationAttribute
from .fixtures import data


def test_construct_fyle_payload(api_client, test_connection, mocker, create_temp_workspace, add_sage300_creds, add_fyle_credentials, add_project_mappings):
project = Project(1, 'PROJECT', None)

# create new case
paginated_destination_attributes = DestinationAttribute.objects.filter(workspace_id=1, attribute_type='PROJECT')

existing_fyle_attributes_map = {}
is_auto_sync_status_allowed = project.get_auto_sync_permission()

fyle_payload = project.construct_fyle_payload(
paginated_destination_attributes,
existing_fyle_attributes_map,
is_auto_sync_status_allowed
)

assert fyle_payload == data['create_fyle_project_payload_create_new_case']

# disable case
DestinationAttribute.objects.filter(
workspace_id=1,
attribute_type='PROJECT',
value__in=['Platform APIs']
).update(active=False)

paginated_destination_attributes = DestinationAttribute.objects.filter(workspace_id=1, attribute_type='PROJECT')

paginated_destination_attribute_values = [attribute.value for attribute in paginated_destination_attributes]

existing_fyle_attributes_map = project.get_existing_fyle_attributes(paginated_destination_attribute_values)

fyle_payload = project.construct_fyle_payload(
paginated_destination_attributes,
existing_fyle_attributes_map,
True
)

assert fyle_payload == data['create_fyle_project_payload_create_disable_case']
Empty file.

0 comments on commit 956b860

Please sign in to comment.