Skip to content

Commit

Permalink
support for standard and normal categories and cost code
Browse files Browse the repository at this point in the history
  • Loading branch information
NileshPant1999 committed Oct 31, 2023
1 parent 36f7a24 commit 2d16e78
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 10 deletions.
37 changes: 37 additions & 0 deletions apps/fyle/migrations/0002_dependentfieldsetting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Generated by Django 4.1.2 on 2023-10-30 18:07

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


class Migration(migrations.Migration):

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

operations = [
migrations.CreateModel(
name='DependentFieldSetting',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, help_text='Created at datetime')),
('updated_at', models.DateTimeField(auto_now=True, help_text='Updated at datetime')),
('id', models.AutoField(primary_key=True, serialize=False)),
('is_import_enabled', sage_desktop_api.models.fields.BooleanFalseField(default=True, help_text='Is Import Enabled')),
('project_field_id', sage_desktop_api.models.fields.IntegerNotNullField(help_text='Fyle Source Field ID')),
('cost_code_field_name', sage_desktop_api.models.fields.StringNotNullField(help_text='Fyle Cost Code Field Name', max_length=255)),
('cost_code_field_id', sage_desktop_api.models.fields.StringNotNullField(help_text='Fyle Cost Code Field ID', max_length=255)),
('cost_code_placeholder', models.TextField(blank=True, help_text='Placeholder for Cost code', null=True)),
('category_field_name', sage_desktop_api.models.fields.StringNotNullField(help_text='Fyle Cost Type Field Name', max_length=255)),
('category_field_id', sage_desktop_api.models.fields.StringNotNullField(help_text='Fyle Cost Type Field ID', max_length=255)),
('category_placeholder', models.TextField(blank=True, help_text='Placeholder for Cost Type', null=True)),
('last_successful_import_at', sage_desktop_api.models.fields.CustomDateTimeField(help_text='Last Successful Import At', null=True)),
('workspace', models.OneToOneField(help_text='Reference to Workspace model', on_delete=django.db.models.deletion.PROTECT, to='workspaces.workspace')),
],
options={
'db_table': 'dependent_field_settings',
},
),
]
23 changes: 22 additions & 1 deletion apps/fyle/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
CustomJsonField,
CustomDateTimeField,
CustomEmailField,
FloatNullField
FloatNullField,
IntegerNotNullField,
)
from apps.workspaces.models import BaseModel, BaseForeignWorkspaceModel

Expand Down Expand Up @@ -104,6 +105,26 @@ class Meta:
db_table = 'expenses'


class DependentFieldSetting(BaseModel):
"""
Fyle Dependent Fields
DB Table: dependent_field_settings:
"""
id = models.AutoField(primary_key=True)
is_import_enabled = BooleanFalseField(help_text='Is Import Enabled')
project_field_id = IntegerNotNullField(help_text='Fyle Source Field ID')
cost_code_field_name = StringNotNullField(help_text='Fyle Cost Code Field Name')
cost_code_field_id = StringNotNullField(help_text='Fyle Cost Code Field ID')
cost_code_placeholder = models.TextField(blank=True, null=True, help_text='Placeholder for Cost code')
category_field_name = StringNotNullField(max_length=255, help_text='Fyle Cost Type Field Name')
category_field_id = StringNotNullField(help_text='Fyle Cost Type Field ID')
category_placeholder = models.TextField(blank=True, null=True, help_text='Placeholder for Cost Type')
last_successful_import_at = CustomDateTimeField(null=True, help_text='Last Successful Import At')

class Meta:
db_table = 'dependent_field_settings'


class Reimbursement:
"""
Creating a dummy class to be able to user
Expand Down
4 changes: 2 additions & 2 deletions apps/mappings/imports/modules/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,11 @@ def sync_destination_attributes(self, sage300_attribute_type: str):
sage300_connection = SageDesktopConnector(credentials_object=sage300_credentials, workspace_id=self.workspace_id)

sync_methods = {
'CATEGORY': sage300_connection.sync_categories,
'STANDARD_CATEGORY': sage300_connection.sync_standard_categories,
'JOB': sage300_connection.sync_jobs,
'COMMITMENT': sage300_connection.sync_commitments,
'VENDOR': sage300_connection.sync_vendors,
'COST_CODES': sage300_connection.sync_cost_codes,
'STANDARD_COST_CODES': sage300_connection.sync_standard_cost_codes,
'ACCOUNT': sage300_connection.sync_accounts,
}

Expand Down
2 changes: 1 addition & 1 deletion apps/sage300/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def sync_dimensions(sage300_credential: Sage300Credential, workspace_id: int) ->
sage300_connection = import_string('apps.sage300.utils.SageDesktopConnector')(sage300_credential, workspace_id)

# List of dimensions to sync
dimensions = ['accounts', 'vendors', 'commitments', 'jobs', 'standard_categories', 'standard_cost_codes']
dimensions = ['categories']

for dimension in dimensions:
try:
Expand Down
35 changes: 35 additions & 0 deletions apps/sage300/migrations/0002_sage300categories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 4.1.2 on 2023-10-31 06:48

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


class Migration(migrations.Migration):

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

operations = [
migrations.CreateModel(
name='Sage300Categories',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, help_text='Created at datetime')),
('updated_at', models.DateTimeField(auto_now=True, help_text='Updated at datetime')),
('id', models.AutoField(primary_key=True, serialize=False)),
('job_id', sage_desktop_api.models.fields.StringNotNullField(help_text='Sage300 Job Id', max_length=255)),
('job_name', sage_desktop_api.models.fields.StringNotNullField(help_text='Sage300 Job Name', max_length=255)),
('cost_code_id', sage_desktop_api.models.fields.StringNotNullField(help_text='Sage300 Cost Code Id', max_length=255)),
('cost_code_name', sage_desktop_api.models.fields.StringNotNullField(help_text='Sage300 Cost Code Name', max_length=255)),
('name', sage_desktop_api.models.fields.StringNotNullField(help_text='Sage300 Cost Type Name', max_length=255)),
('category_id', sage_desktop_api.models.fields.StringNotNullField(help_text='Sage300 Category Id', max_length=255)),
('status', sage_desktop_api.models.fields.BooleanFalseField(default=True, help_text='Sage300 Cost Type Status')),
('workspace', models.ForeignKey(help_text='Reference to Workspace model', on_delete=django.db.models.deletion.PROTECT, to='workspaces.workspace')),
],
options={
'db_table': 'sage300_categories',
},
),
]
109 changes: 107 additions & 2 deletions apps/sage300/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
from typing import Dict, List
from django.db import models
from apps.workspaces.models import BaseModel

from fyle_accounting_mappings.models import (
DestinationAttribute
)

from apps.workspaces.models import BaseModel, BaseForeignWorkspaceModel
from sage_desktop_api.models.fields import (
StringNotNullField,
CustomDateTimeField,
FloatNullField,
IntegerNullField,
TextNotNullField
TextNotNullField,
BooleanFalseField
)
from apps.accounting_exports.models import AccountingExport

Expand Down Expand Up @@ -93,3 +100,101 @@ class DirectCost(BaseModel):

class Meta:
db_table = 'direct_cost'


class Sage300Categories(BaseForeignWorkspaceModel):
"""
Categories Table Model Class
"""

id = models.AutoField(primary_key=True)
job_id = StringNotNullField(help_text='Sage300 Job Id')
job_name = StringNotNullField(help_text='Sage300 Job Name')
cost_code_id = StringNotNullField(help_text='Sage300 Cost Code Id')
cost_code_name = StringNotNullField(help_text='Sage300 Cost Code Name')
name = StringNotNullField(help_text='Sage300 Cost Type Name')
category_id = StringNotNullField(help_text='Sage300 Category Id')
status = BooleanFalseField(help_text='Sage300 Cost Type Status')

class Meta:
db_table = 'sage300_categories'

@staticmethod
def bulk_create_or_update(categories_generator: List[Dict], workspace_id: int):
"""
Bulk create or update cost types
"""

list_of_categories = []
for categories in categories_generator:
list_of_categories.append(categories)

record_number_list = [category.id for category in list_of_categories]

filters = {
'category_id__in': record_number_list,
'workspace_id': workspace_id
}

existing_categories = Sage300Categories.objects.filter(**filters).values(
'id',
'category_id',
'name',
'status'
)

existing_cost_type_record_numbers = []
primary_key_map = {}

for existing_category in existing_categories:
existing_cost_type_record_numbers.append(existing_category['category_id'])
primary_key_map[existing_category['category_id']] = {
'id': existing_category['id'],
'name': existing_category['name'],
'status': existing_category['status'],
}

category_to_be_created = []
category_to_be_updated = []

# Retrieve job names and cost code names in a single query
cost_code_ids = [category.cost_code_id for category in list_of_categories]
job_ids = [category.job_id for category in list_of_categories]

job_name_mapping = {attr.destination_id: attr.value for attr in DestinationAttribute.objects.filter(destination_id__in=job_ids)}
cost_code_name_mapping = {attr.destination_id: attr.value for attr in DestinationAttribute.objects.filter(destination_id__in=cost_code_ids)}

for category in list_of_categories:
job_name = job_name_mapping.get(category.job_id)
cost_code_name = cost_code_name_mapping.get(category.cost_code_id)
category_object = Sage300Categories(
job_id=category.job_id,
job_name=job_name,
cost_code_id=category.cost_code_id,
cost_code_name=cost_code_name,
name=category.name,
status=category.is_active,
category_id=category.id,
workspace_id=workspace_id
)

if category.id not in existing_cost_type_record_numbers:
category_to_be_created.append(category_object)

elif category.id in primary_key_map.keys() and (
category.name != primary_key_map[category.id]['name'] or category.is_active != primary_key_map[category.id]['status']
):
category_object.id = primary_key_map[category.id]['category_id']
category_to_be_updated.append(category_object)

if category_to_be_created:
Sage300Categories.objects.bulk_create(category_to_be_created, batch_size=2000)

if category_to_be_updated:
Sage300Categories.objects.bulk_update(
category_to_be_updated, fields=[
'job_id', 'job_name', 'cost_code_id', 'cost_code_name',
'name', 'status', 'category_id'
],
batch_size=2000
)
16 changes: 12 additions & 4 deletions apps/sage300/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from fyle_accounting_mappings.models import DestinationAttribute
from apps.workspaces.models import Sage300Credential
from sage_desktop_sdk.sage_desktop_sdk import SageDesktopSDK
from apps.sage300.models import Sage300Categories


class SageDesktopConnector:
Expand Down Expand Up @@ -106,7 +107,7 @@ def sync_standard_cost_codes(self):
"""
Synchronize standard cost codes from Sage Desktop SDK to your application
"""
cost_codes = self.connection.jobs.get_all_costcodes()
cost_codes = self.connection.jobs.get_standard_costcodes()
field_names = ['code', 'version', 'is_standard', 'description']
self._sync_data(cost_codes, 'STANDARD_COST_CODE', 'standard_cost_code', self.workspace_id, field_names)
return []
Expand All @@ -115,7 +116,7 @@ def sync_standard_categories(self):
"""
Synchronize standard categories from Sage Desktop SDK to your application
"""
categories = self.connection.jobs.get_all_categories()
categories = self.connection.jobs.get_standard_categories()
field_names = ['code', 'version', 'description', 'accumulation_name']
self._sync_data(categories, 'STANDARD_CATEGORY', 'standard_category', self.workspace_id, field_names)
return []
Expand All @@ -136,7 +137,14 @@ def sync_cost_codes(self):
"""
Synchronize cost codes from Sage Desktop SDK to your application
"""
cost_codes = self.connection.jobs.get_all_costcodes()
field_names = ['code', 'version', 'job_id', 'standard_costcode_id']
cost_codes = self.connection.cost_codes.get_all_costcodes()
field_names = ['code', 'version', 'job_id']
self._sync_data(cost_codes, 'COST_CODE', 'cost_code', self.workspace_id, field_names)
return []

def sync_categories(self):
"""
Synchronize categories from Sage Desktop SDK to your application
"""
categories = self.connection.categories.get_all_categories()
Sage300Categories.bulk_create_or_update(categories, self.workspace_id)
2 changes: 2 additions & 0 deletions apps/sage300/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class ImportSage300AttributesView(generics.CreateAPIView):
"""
Import Sage300 Attributes View
"""
authentication_classes = []
permission_classes = []
serializer_class = ImportSage300AttributesSerializer


Expand Down

0 comments on commit 2d16e78

Please sign in to comment.