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

Mapping settings added to import settings #74

Merged
merged 4 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions apps/workspaces/migrations/0003_alter_importsetting_workspace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.1.2 on 2023-11-06 10:33

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


class Migration(migrations.Migration):

dependencies = [
('workspaces', '0002_sage300credential_importsetting_fylecredential_and_more'),
]

operations = [
migrations.AlterField(
model_name='importsetting',
name='workspace',
field=models.OneToOneField(help_text='Reference to Workspace model', on_delete=django.db.models.deletion.PROTECT, related_name='import_settings', to='workspaces.workspace'),
),
]
1 change: 1 addition & 0 deletions apps/workspaces/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class ImportSetting(BaseModel):
id = models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)
import_categories = BooleanFalseField(help_text='toggle for import of chart of accounts from sage300')
import_vendors_as_merchants = BooleanFalseField(help_text='toggle for import of vendors as merchant from sage300')
workspace = models.OneToOneField(Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model', related_name="import_settings")

class Meta:
db_table = 'import_settings'
Expand Down
132 changes: 116 additions & 16 deletions apps/workspaces/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
from django.conf import settings
from django.core.cache import cache
from rest_framework import serializers
from fyle_accounting_mappings.models import MappingSetting
from fyle_rest_auth.helpers import get_fyle_admin
from fyle_rest_auth.models import AuthToken
from fyle_accounting_mappings.models import ExpenseAttribute
from django.db import transaction
from django.db.models import Q

from sage_desktop_api.utils import assert_valid
from sage_desktop_sdk.sage_desktop_sdk import SageDesktopSDK
Expand All @@ -27,6 +30,7 @@
)
from apps.users.models import User
from apps.fyle.helpers import get_cluster_domain
from apps.workspaces.triggers import ImportSettingsTrigger


class WorkspaceSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -157,32 +161,128 @@ def create(self, validated_data):
return export_settings


class ImportSettingsSerializer(serializers.ModelSerializer):
class MappingSettingFilteredListSerializer(serializers.ListSerializer):
"""
Export Settings serializer
Serializer to filter the active system, which is a boolen field in
System Model. The value argument to to_representation() method is
the model instance
"""
def to_representation(self, data):
data = data.filter(~Q(
destination_field__in=[
'ACCOUNT',
'CCC_ACCOUNT',
'CHARGE_CARD_NUMBER',
'EMPLOYEE',
'EXPENSE_TYPE',
'TAX_DETAIL',
'VENDOR'
])
)
return super(MappingSettingFilteredListSerializer, self).to_representation(data)


class MappingSettingSerializer(serializers.ModelSerializer):
class Meta:
model = MappingSetting
list_serializer_class = MappingSettingFilteredListSerializer
fields = [
'source_field',
'destination_field',
'import_to_fyle',
'is_custom',
'source_placeholder'
]


class ImportSettingFilterSerializer(serializers.ModelSerializer):
"""
Import Settings Filtered serializer
"""
class Meta:
model = ImportSetting
fields = '__all__'
read_only_fields = ('id', 'workspace', 'created_at', 'updated_at')
fields = [
'import_categories',
'import_vendors_as_merchants',
]

def create(self, validated_data):

class ImportSettingsSerializer(serializers.ModelSerializer):
"""
Import Settings serializer
"""
import_settings = ImportSettingFilterSerializer()
mapping_settings = MappingSettingSerializer(many=True)
workspace_id = serializers.SerializerMethodField()

class Meta:
model = Workspace
fields = [
'import_settings',
'mapping_settings',
'workspace_id'
]
read_only_fields = ['workspace_id']

def get_workspace_id(self, instance):
return instance.id

def update(self, instance, validated):
"""
Create Export Settings
Create Import Settings
"""

workspace_id = self.context['request'].parser_context.get('kwargs').get('workspace_id')
import_settings, _ = ImportSetting.objects.update_or_create(
workspace_id=workspace_id,
defaults=validated_data
)
mapping_settings = validated.pop('mapping_settings')
import_settings = validated.pop('import_settings')
# dependent_field_settings = validated.pop('dependent_field_settings')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed in next PR


with transaction.atomic():
print("inside function")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed in next PR

ImportSetting.objects.update_or_create(
workspace_id=instance.id,
defaults={
'import_categories': import_settings.get('import_categories'),
'import_vendors_as_merchants': import_settings.get('import_vendors_as_merchants')
}
)

trigger: ImportSettingsTrigger = ImportSettingsTrigger(
mapping_settings=mapping_settings,
workspace_id=instance.id
)

for setting in mapping_settings:
MappingSetting.objects.update_or_create(
destination_field=setting['destination_field'],
workspace_id=instance.id,
defaults={
'source_field': setting['source_field'],
'import_to_fyle': setting['import_to_fyle'] if 'import_to_fyle' in setting else False,
'is_custom': setting['is_custom'] if 'is_custom' in setting else False,
'source_placeholder': setting['source_placeholder'] if 'source_placeholder' in setting else None
}
)

trigger.post_save_mapping_settings()

# Update workspace onboarding state
workspace = import_settings.workspace
if workspace.onboarding_state == 'IMPORT_SETTINGS':
workspace.onboarding_state = 'ADVANCED_SETTINGS'
workspace.save()
if instance.onboarding_state == 'IMPORT_SETTINGS':
instance.onboarding_state = 'ADVANCED_SETTINGS'
instance.save()

return instance

def validate(self, data):
if not data.get('import_settings'):
raise serializers.ValidationError('Import Settings are required')

if data.get('mapping_settings') is None:
raise serializers.ValidationError('Mapping settings are required')

if not data.get('dependent_field_settings'):
pass

return import_settings
return data


class AdvancedSettingSerializer(serializers.ModelSerializer):
Expand Down
43 changes: 43 additions & 0 deletions apps/workspaces/triggers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from typing import Dict, List
from django.db.models import Q

# from apps.mappings.helpers import schedule_or_delete_fyle_import_tasks
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed in next PR

from fyle_accounting_mappings.models import MappingSetting


class ImportSettingsTrigger:
"""
All the post save actions of Import Settings API
"""
def __init__(self, mapping_settings: List[Dict], workspace_id):
self.__mapping_settings = mapping_settings
self.__workspace_id = workspace_id

def post_save_mapping_settings(self):
"""
Post save actions for mapping settings
Here we need to clear out the data from the mapping-settings table for consecutive runs.
"""
# We first need to avoid deleting mapping-settings that are always necessary.
destination_fields = [
'ACCOUNT',
'CCC_ACCOUNT',
'CHARGE_CARD_NUMBER',
'EMPLOYEE',
'EXPENSE_TYPE',
'TAX_DETAIL',
'VENDOR'
]

# Here we are filtering out the mapping_settings payload and adding the destination-fields that are present in the payload
# So that we avoid deleting them.
for setting in self.__mapping_settings:
if setting['destination_field'] not in destination_fields:
destination_fields.append(setting['destination_field'])

# Now that we have all the system necessary mapping-settings and the mapping-settings in the payload
# This query will take care of deleting all the redundant mapping-settings that are not required.
MappingSetting.objects.filter(
~Q(destination_field__in=destination_fields),
workspace_id=self.__workspace_id
).delete()
9 changes: 4 additions & 5 deletions apps/workspaces/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
Workspace,
Sage300Credential,
ExportSetting,
ImportSetting,
AdvancedSetting
)
from apps.workspaces.serializers import (
Expand Down Expand Up @@ -99,14 +98,14 @@ class ExportSettingView(generics.CreateAPIView, generics.RetrieveAPIView):
queryset = ExportSetting.objects.all()


class ImportSettingView(generics.CreateAPIView, generics.RetrieveAPIView):
class ImportSettingView(generics.RetrieveUpdateAPIView):
"""
Retrieve or Create Export Settings
Retrieve or Create Import Settings
"""
serializer_class = ImportSettingsSerializer
lookup_field = 'workspace_id'

queryset = ImportSetting.objects.all()
def get_object(self):
return Workspace.objects.filter(id=self.kwargs['workspace_id']).first()


class AdvancedSettingView(generics.CreateAPIView, generics.RetrieveAPIView):
Expand Down
2 changes: 1 addition & 1 deletion centralized_run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ python manage.py migrate
python manage.py createcachetable --database cache_db

# Running development server
gunicorn -c gunicorn_config.py sage_desktop_api.wsgi -b 0.0.0.0:8008
gunicorn -c gunicorn_config.py sage_desktop_api.wsgi -b 0.0.0.0:8010
25 changes: 1 addition & 24 deletions tests/test_workspaces/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
Workspace,
Sage300Credential,
ExportSetting,
ImportSetting,
AdvancedSetting
)

Expand Down Expand Up @@ -191,29 +190,7 @@ def test_import_settings(api_client, test_connection):
'''
Test export settings
'''
url = reverse('workspaces')
api_client.credentials(HTTP_AUTHORIZATION='Bearer {}'.format(test_connection.access_token))
response = api_client.post(url)
workspace_id = response.data['id']
url = reverse(
'import-settings',
kwargs={'workspace_id': workspace_id}
)

payload = {
'import_categories': True,
'import_vendors_as_merchants': True
}
response = api_client.post(url, payload)
import_settings = ImportSetting.objects.filter(workspace_id=workspace_id).first()
assert response.status_code == 201
assert import_settings.import_categories is True
assert import_settings.import_vendors_as_merchants is True

response = api_client.get(url)
assert response.status_code == 200
assert import_settings.import_categories is True
assert import_settings.import_vendors_as_merchants is True
pass
ruuushhh marked this conversation as resolved.
Show resolved Hide resolved


def test_advanced_settings(api_client, test_connection):
Expand Down
Loading