From 7bae7c8b3c43a789ef3350f31d81db68bd619942 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 17:03:01 +0530 Subject: [PATCH 01/16] Feat: Add Mixin to add created_by and updated_by for configuration models --- fyle_accounting_mappings/models.py | 55 ++++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 5c96268..80a1689 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -888,3 +888,58 @@ def bulk_create_ccc_category_mappings(workspace_id: int): CategoryMapping.objects.bulk_update( mapping_updation_batch, fields=['destination_account'], batch_size=50 ) + + +class AutoUserTrackManager(models.Manager): + def update_or_create(self, defaults=None, **kwargs): + """ + Overrides the default update_or_create to handle 'user' keyword argument. + """ + user = kwargs.pop('user', None) + defaults = defaults or {} + + if user and hasattr(user, 'email'): + defaults['updated_by'] = user.email + + instance, created = super().update_or_create(defaults=defaults, **kwargs) + + if created and user and hasattr(user, 'email'): + instance.created_by = user.email + instance.save(user=user) + + return instance, created + +class AutoUserTrackModelMixin(models.Model): + """ + Mixin to automatically set created_by and updated_by fields. + Stores only the user's email. + """ + created_by = models.CharField( + max_length=255, + null=True, + blank=True, + help_text="Email of the user who created this record" + ) + updated_by = models.CharField( + max_length=255, + null=True, + blank=True, + help_text="Email of the user who last updated this record" + ) + + objects = AutoUserTrackManager() + + class Meta: + abstract = True + + def save(self, *args, **kwargs): + """ + Override the save method to set created_by and updated_by fields. + Expects a 'user' keyword argument containing the user instance. + """ + user = kwargs.pop('user', None) + if user and hasattr(user, 'email'): + if not self.pk: + self.created_by = user.email + self.updated_by = user.email + super().save(*args, **kwargs) diff --git a/setup.py b/setup.py index e2165c1..03509bd 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name='fyle-accounting-mappings', - version='1.35.0', + version='1.36.0', author='Shwetabh Kumar', author_email='shwetabh.kumar@fyle.in', description='Django application to store the fyle accounting mappings in a generic manner', From fafa1603d724d6c22d005feb015d6f97b81b0c2b Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 17:07:05 +0530 Subject: [PATCH 02/16] change name --- fyle_accounting_mappings/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 80a1689..c29017a 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -890,7 +890,7 @@ def bulk_create_ccc_category_mappings(workspace_id: int): ) -class AutoUserTrackManager(models.Manager): +class AutoAddCreateUpdateInfoManager(models.Manager): def update_or_create(self, defaults=None, **kwargs): """ Overrides the default update_or_create to handle 'user' keyword argument. @@ -909,7 +909,7 @@ def update_or_create(self, defaults=None, **kwargs): return instance, created -class AutoUserTrackModelMixin(models.Model): +class AutoAddCreateUpdateInfoMixin(models.Model): """ Mixin to automatically set created_by and updated_by fields. Stores only the user's email. @@ -927,7 +927,7 @@ class AutoUserTrackModelMixin(models.Model): help_text="Email of the user who last updated this record" ) - objects = AutoUserTrackManager() + objects = AutoAddCreateUpdateInfoManager() class Meta: abstract = True From d95af52822c1694922a782c38d10a98ebea233ee Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 17:09:48 +0530 Subject: [PATCH 03/16] fix pylint --- fyle_accounting_mappings/models.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index c29017a..b156f1b 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -895,36 +895,38 @@ def update_or_create(self, defaults=None, **kwargs): """ Overrides the default update_or_create to handle 'user' keyword argument. """ - user = kwargs.pop('user', None) + user = kwargs.pop("user", None) defaults = defaults or {} - - if user and hasattr(user, 'email'): - defaults['updated_by'] = user.email - + + if user and hasattr(user, "email"): + defaults["updated_by"] = user.email + instance, created = super().update_or_create(defaults=defaults, **kwargs) - - if created and user and hasattr(user, 'email'): + + if created and user and hasattr(user, "email"): instance.created_by = user.email instance.save(user=user) - + return instance, created + class AutoAddCreateUpdateInfoMixin(models.Model): """ Mixin to automatically set created_by and updated_by fields. Stores only the user's email. """ + created_by = models.CharField( max_length=255, null=True, blank=True, - help_text="Email of the user who created this record" + help_text="Email of the user who created this record", ) updated_by = models.CharField( max_length=255, null=True, blank=True, - help_text="Email of the user who last updated this record" + help_text="Email of the user who last updated this record", ) objects = AutoAddCreateUpdateInfoManager() @@ -937,8 +939,8 @@ def save(self, *args, **kwargs): Override the save method to set created_by and updated_by fields. Expects a 'user' keyword argument containing the user instance. """ - user = kwargs.pop('user', None) - if user and hasattr(user, 'email'): + user = kwargs.pop("user", None) + if user and hasattr(user, "email"): if not self.pk: self.created_by = user.email self.updated_by = user.email From 001428a7aa83da2279970221bfcb2c7acb25e2d5 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 18:43:11 +0530 Subject: [PATCH 04/16] fix linting --- fyle_accounting_mappings/models.py | 820 ++++++++++++++++++++--------- 1 file changed, 567 insertions(+), 253 deletions(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index b156f1b..4ff5c28 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -10,7 +10,7 @@ from .utils import assert_valid -workspace_models = importlib.import_module("apps.workspaces.models") +workspace_models = importlib.import_module('apps.workspaces.models') Workspace = workspace_models.Workspace @@ -20,19 +20,23 @@ def validate_mapping_settings(mappings_settings: List[Dict]): row = 0 for mappings_setting in mappings_settings: - if ('source_field' not in mappings_setting) and (not mappings_setting['source_field']): - bulk_errors.append({ - 'row': row, - 'value': None, - 'message': 'source field cannot be empty' - }) - - if ('destination_field' not in mappings_setting) and (not mappings_setting['destination_field']): - bulk_errors.append({ - 'row': row, - 'value': None, - 'message': 'destination field cannot be empty' - }) + if ('source_field' not in mappings_setting) and ( + not mappings_setting['source_field'] + ): + bulk_errors.append( + {'row': row, 'value': None, 'message': 'source field cannot be empty'} + ) + + if ('destination_field' not in mappings_setting) and ( + not mappings_setting['destination_field'] + ): + bulk_errors.append( + { + 'row': row, + 'value': None, + 'message': 'destination field cannot be empty', + } + ) row = row + 1 @@ -40,7 +44,9 @@ def validate_mapping_settings(mappings_settings: List[Dict]): raise BulkError('Errors while creating settings', bulk_errors) -def create_mappings_and_update_flag(mapping_batch: list, set_auto_mapped_flag: bool = True, **kwargs): +def create_mappings_and_update_flag( + mapping_batch: list, set_auto_mapped_flag: bool = True, **kwargs +): model_type = kwargs['model_type'] if 'model_type' in kwargs else Mapping if model_type == CategoryMapping: mappings = CategoryMapping.objects.bulk_create(mapping_batch, batch_size=50) @@ -53,20 +59,30 @@ def create_mappings_and_update_flag(mapping_batch: list, set_auto_mapped_flag: b for mapping in mappings: expense_attributes_to_be_updated.append( ExpenseAttribute( - id=mapping.source_category.id if model_type == CategoryMapping else mapping.source.id, - auto_mapped=True + id=( + mapping.source_category.id + if model_type == CategoryMapping + else mapping.source.id + ), + auto_mapped=True, ) ) if expense_attributes_to_be_updated: ExpenseAttribute.objects.bulk_update( - expense_attributes_to_be_updated, fields=['auto_mapped'], batch_size=50) + expense_attributes_to_be_updated, fields=['auto_mapped'], batch_size=50 + ) return mappings -def construct_mapping_payload(employee_source_attributes: list, employee_mapping_preference: str, - destination_id_value_map: dict, destination_type: str, workspace_id: int): +def construct_mapping_payload( + employee_source_attributes: list, + employee_mapping_preference: str, + destination_id_value_map: dict, + destination_type: str, + workspace_id: int, +): existing_source_ids = get_existing_source_ids(destination_type, workspace_id) mapping_batch = [] @@ -89,7 +105,7 @@ def construct_mapping_payload(employee_source_attributes: list, employee_mapping destination_type=destination_type, source_id=source_attribute.id, destination_id=destination_id, - workspace_id=workspace_id + workspace_id=workspace_id, ) ) @@ -98,7 +114,9 @@ def construct_mapping_payload(employee_source_attributes: list, employee_mapping def get_existing_source_ids(destination_type: str, workspace_id: int): existing_mappings = Mapping.objects.filter( - source_type='EMPLOYEE', destination_type=destination_type, workspace_id=workspace_id + source_type='EMPLOYEE', + destination_type=destination_type, + workspace_id=workspace_id, ).all() existing_source_ids = [] @@ -112,28 +130,45 @@ class ExpenseAttributesDeletionCache(models.Model): id = models.AutoField(primary_key=True) category_ids = ArrayField(default=[], base_field=models.CharField(max_length=255)) project_ids = ArrayField(default=[], base_field=models.CharField(max_length=255)) - workspace = models.OneToOneField(Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') + workspace = models.OneToOneField( + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' + ) class Meta: db_table = 'expense_attributes_deletion_cache' class ExpenseAttribute(models.Model): - """ + ''' Fyle Expense Attributes - """ + ''' + id = models.AutoField(primary_key=True) - attribute_type = models.CharField(max_length=255, help_text='Type of expense attribute') - display_name = models.CharField(max_length=255, help_text='Display name of expense attribute') + attribute_type = models.CharField( + max_length=255, help_text='Type of expense attribute' + ) + display_name = models.CharField( + max_length=255, help_text='Display name of expense attribute' + ) value = models.CharField(max_length=1000, help_text='Value of expense attribute') source_id = models.CharField(max_length=255, help_text='Fyle ID') - workspace = models.ForeignKey(Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') - auto_mapped = models.BooleanField(default=False, help_text='Indicates whether the field is auto mapped or not') - auto_created = models.BooleanField(default=False, - help_text='Indicates whether the field is auto created by the integration') - active = models.BooleanField(null=True, help_text='Indicates whether the fields is active or not') + workspace = models.ForeignKey( + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' + ) + auto_mapped = models.BooleanField( + default=False, help_text='Indicates whether the field is auto mapped or not' + ) + auto_created = models.BooleanField( + default=False, + help_text='Indicates whether the field is auto created by the integration', + ) + active = models.BooleanField( + null=True, help_text='Indicates whether the fields is active or not' + ) detail = JSONField(help_text='Detailed expense attributes payload', null=True) - created_at = models.DateTimeField(auto_now_add=True, help_text='Created at datetime') + 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') class Meta: @@ -142,9 +177,9 @@ class Meta: @staticmethod def create_or_update_expense_attribute(attribute: Dict, workspace_id): - """ + ''' Get or create expense attribute - """ + ''' expense_attribute, _ = ExpenseAttribute.objects.update_or_create( attribute_type=attribute['attribute_type'], value=attribute['value'], @@ -153,19 +188,21 @@ def create_or_update_expense_attribute(attribute: Dict, workspace_id): 'active': attribute['active'] if 'active' in attribute else None, 'source_id': attribute['source_id'], 'display_name': attribute['display_name'], - 'detail': attribute['detail'] if 'detail' in attribute else None - } + 'detail': attribute['detail'] if 'detail' in attribute else None, + }, ) return expense_attribute @staticmethod def bulk_update_deleted_expense_attributes(attribute_type: str, workspace_id: int): - """ + ''' Bulk update deleted expense attributes :param attribute_type: Attribute type :param workspace_id: Workspace Id - """ - expense_attributes_deletion_cache = ExpenseAttributesDeletionCache.objects.get(workspace_id=workspace_id) + ''' + expense_attributes_deletion_cache = ExpenseAttributesDeletionCache.objects.get( + workspace_id=workspace_id + ) attributes_to_be_updated = [] if attribute_type == 'CATEGORY': @@ -184,20 +221,23 @@ def bulk_update_deleted_expense_attributes(attribute_type: str, workspace_id: in for attribute in deleted_attributes: attributes_to_be_updated.append( ExpenseAttribute( - id=attribute.id, - active=False, - updated_at=datetime.now() + id=attribute.id, active=False, updated_at=datetime.now() ) ) if attributes_to_be_updated: ExpenseAttribute.objects.bulk_update( - attributes_to_be_updated, fields=['active', 'updated_at'], batch_size=50) + attributes_to_be_updated, fields=['active', 'updated_at'], batch_size=50 + ) @staticmethod def bulk_create_or_update_expense_attributes( - attributes: List[Dict], attribute_type: str, workspace_id: int, update: bool = False): - """ + attributes: List[Dict], + attribute_type: str, + workspace_id: int, + update: bool = False, + ): + ''' Create Expense Attributes in bulk :param update: Update Pre-existing records or not :param attribute_type: Attribute type @@ -210,12 +250,14 @@ def bulk_create_or_update_expense_attributes( }] :param workspace_id: Workspace Id :return: created / updated attributes - """ + ''' attribute_value_list = [attribute['value'] for attribute in attributes] existing_attributes = ExpenseAttribute.objects.filter( - value__in=attribute_value_list, attribute_type=attribute_type, - workspace_id=workspace_id).values('id', 'value', 'detail', 'active') + value__in=attribute_value_list, + attribute_type=attribute_type, + workspace_id=workspace_id, + ).values('id', 'value', 'detail', 'active') existing_attribute_values = [] @@ -226,7 +268,7 @@ def bulk_create_or_update_expense_attributes( primary_key_map[existing_attribute['value']] = { 'id': existing_attribute['id'], 'detail': existing_attribute['detail'], - 'active': existing_attribute['active'] + 'active': existing_attribute['active'], } attributes_to_be_created = [] @@ -234,7 +276,10 @@ def bulk_create_or_update_expense_attributes( values_appended = [] for attribute in attributes: - if attribute['value'] not in existing_attribute_values and attribute['value'] not in values_appended: + if ( + attribute['value'] not in existing_attribute_values + and attribute['value'] not in values_appended + ): values_appended.append(attribute['value']) attributes_to_be_created.append( ExpenseAttribute( @@ -244,7 +289,7 @@ def bulk_create_or_update_expense_attributes( source_id=attribute['source_id'], detail=attribute['detail'] if 'detail' in attribute else None, workspace_id=workspace_id, - active=attribute['active'] if 'active' in attribute else None + active=attribute['active'] if 'active' in attribute else None, ) ) else: @@ -253,58 +298,90 @@ def bulk_create_or_update_expense_attributes( ExpenseAttribute( id=primary_key_map[attribute['value']]['id'], source_id=attribute['source_id'], - detail=attribute['detail'] if 'detail' in attribute else None, - active=attribute['active'] if 'active' in attribute else None + detail=( + attribute['detail'] if 'detail' in attribute else None + ), + active=( + attribute['active'] if 'active' in attribute else None + ), ) ) if attributes_to_be_created: - ExpenseAttribute.objects.bulk_create(attributes_to_be_created, batch_size=50) + ExpenseAttribute.objects.bulk_create( + attributes_to_be_created, batch_size=50 + ) if attributes_to_be_updated: ExpenseAttribute.objects.bulk_update( - attributes_to_be_updated, fields=['source_id', 'detail', 'active'], batch_size=50) + attributes_to_be_updated, + fields=['source_id', 'detail', 'active'], + batch_size=50, + ) @staticmethod def get_last_synced_at(attribute_type: str, workspace_id: int): - """ + ''' Get last synced at datetime :param attribute_type: Attribute type :param workspace_id: Workspace Id :return: last_synced_at datetime - """ - return ExpenseAttribute.objects.filter( - workspace_id=workspace_id, - attribute_type=attribute_type - ).order_by('-updated_at').first() + ''' + return ( + ExpenseAttribute.objects.filter( + workspace_id=workspace_id, attribute_type=attribute_type + ) + .order_by('-updated_at') + .first() + ) class DestinationAttribute(models.Model): - """ + ''' Destination Expense Attributes - """ + ''' + id = models.AutoField(primary_key=True) - attribute_type = models.CharField(max_length=255, help_text='Type of expense attribute') - display_name = models.CharField(max_length=255, help_text='Display name of attribute') + attribute_type = models.CharField( + max_length=255, help_text='Type of expense attribute' + ) + display_name = models.CharField( + max_length=255, help_text='Display name of attribute' + ) value = models.CharField(max_length=255, help_text='Value of expense attribute') destination_id = models.CharField(max_length=255, help_text='Destination ID') - workspace = models.ForeignKey(Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') - auto_created = models.BooleanField(default=False, - help_text='Indicates whether the field is auto created by the integration') - active = models.BooleanField(null=True, help_text='Indicates whether the fields is active or not') + workspace = models.ForeignKey( + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' + ) + auto_created = models.BooleanField( + default=False, + help_text='Indicates whether the field is auto created by the integration', + ) + active = models.BooleanField( + null=True, help_text='Indicates whether the fields is active or not' + ) detail = JSONField(help_text='Detailed destination attributes payload', null=True) - code = models.CharField(max_length=255, help_text='Code of the attribute', null=True) - created_at = models.DateTimeField(auto_now_add=True, help_text='Created at datetime') + code = models.CharField( + max_length=255, help_text='Code of the attribute', null=True + ) + 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') class Meta: db_table = 'destination_attributes' - unique_together = ('destination_id', 'attribute_type', 'workspace', 'display_name') + unique_together = ( + 'destination_id', + 'attribute_type', + 'workspace', + 'display_name', + ) @staticmethod def create_or_update_destination_attribute(attribute: Dict, workspace_id): - """ + ''' get or create destination attributes - """ + ''' destination_attribute, _ = DestinationAttribute.objects.update_or_create( attribute_type=attribute['attribute_type'], destination_id=attribute['destination_id'], @@ -314,22 +391,26 @@ def create_or_update_destination_attribute(attribute: Dict, workspace_id): 'display_name': attribute['display_name'], 'value': attribute['value'], 'detail': attribute['detail'] if 'detail' in attribute else None, - 'code': " ".join(attribute['code'].split()) if 'code' in attribute and attribute['code'] else None - } + 'code': ( + ' '.join(attribute['code'].split()) + if 'code' in attribute and attribute['code'] + else None + ), + }, ) return destination_attribute @staticmethod def bulk_create_or_update_destination_attributes( - attributes: List[Dict], - attribute_type: str, - workspace_id: int, - update: bool = False, - display_name: str = None, - attribute_disable_callback_path: str = None, - is_import_to_fyle_enabled: bool = False + attributes: List[Dict], + attribute_type: str, + workspace_id: int, + update: bool = False, + display_name: str = None, + attribute_disable_callback_path: str = None, + is_import_to_fyle_enabled: bool = False, ): - """ + ''' Create Destination Attributes in bulk :param update: Update Pre-existing records or not :param attribute_type: Attribute type @@ -343,32 +424,37 @@ def bulk_create_or_update_destination_attributes( :param workspace_id: Workspace Id :param attributes_disable_callback_path: API func to call when attribute is to be disabled :return: created / updated attributes - """ - attribute_destination_id_list = [attribute['destination_id'] for attribute in attributes] + ''' + attribute_destination_id_list = [ + attribute['destination_id'] for attribute in attributes + ] filters = { 'destination_id__in': attribute_destination_id_list, 'attribute_type': attribute_type, - 'workspace_id': workspace_id + 'workspace_id': workspace_id, } if display_name: filters['display_name'] = display_name - existing_attributes = DestinationAttribute.objects.filter(**filters)\ - .values('id', 'value', 'destination_id', 'detail', 'active', 'code') + existing_attributes = DestinationAttribute.objects.filter(**filters).values( + 'id', 'value', 'destination_id', 'detail', 'active', 'code' + ) existing_attribute_destination_ids = [] primary_key_map = {} for existing_attribute in existing_attributes: - existing_attribute_destination_ids.append(existing_attribute['destination_id']) + existing_attribute_destination_ids.append( + existing_attribute['destination_id'] + ) primary_key_map[existing_attribute['destination_id']] = { 'id': existing_attribute['id'], 'value': existing_attribute['value'], 'detail': existing_attribute['detail'], 'active': existing_attribute['active'], - 'code': existing_attribute['code'] + 'code': existing_attribute['code'], } attributes_to_be_created = [] @@ -377,8 +463,10 @@ def bulk_create_or_update_destination_attributes( destination_ids_appended = [] for attribute in attributes: - if attribute['destination_id'] not in existing_attribute_destination_ids \ - and attribute['destination_id'] not in destination_ids_appended: + if ( + attribute['destination_id'] not in existing_attribute_destination_ids + and attribute['destination_id'] not in destination_ids_appended + ): destination_ids_appended.append(attribute['destination_id']) attributes_to_be_created.append( DestinationAttribute( @@ -389,60 +477,115 @@ def bulk_create_or_update_destination_attributes( detail=attribute['detail'] if 'detail' in attribute else None, workspace_id=workspace_id, active=attribute['active'] if 'active' in attribute else None, - code=" ".join(attribute['code'].split()) if 'code' in attribute and attribute['code'] else None + code=( + ' '.join(attribute['code'].split()) + if 'code' in attribute and attribute['code'] + else None + ), ) ) else: - if attribute_disable_callback_path and is_import_to_fyle_enabled and ( - (attribute['value'] and primary_key_map[attribute['destination_id']]['value'] and attribute['value'].lower() != primary_key_map[attribute['destination_id']]['value'].lower()) - or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) + if ( + attribute_disable_callback_path + and is_import_to_fyle_enabled + and ( + ( + attribute['value'] + and primary_key_map[attribute['destination_id']]['value'] + and attribute['value'].lower() + != primary_key_map[attribute['destination_id']][ + 'value' + ].lower() + ) + or ( + 'code' in attribute + and attribute['code'] + and attribute['code'] + != primary_key_map[attribute['destination_id']]['code'] + ) + ) ): attributes_to_disable[attribute['destination_id']] = { 'value': primary_key_map[attribute['destination_id']]['value'], 'updated_value': attribute['value'], 'code': primary_key_map[attribute['destination_id']]['code'], - 'updated_code': attribute['code'] + 'updated_code': attribute['code'], } if update and ( - (attribute['value'] != primary_key_map[attribute['destination_id']]['value']) - or ('detail' in attribute and attribute['detail'] != primary_key_map[attribute['destination_id']]['detail']) - or ('active' in attribute and attribute['active'] != primary_key_map[attribute['destination_id']]['active']) - or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) + ( + attribute['value'] + != primary_key_map[attribute['destination_id']]['value'] + ) + or ( + 'detail' in attribute + and attribute['detail'] + != primary_key_map[attribute['destination_id']]['detail'] + ) + or ( + 'active' in attribute + and attribute['active'] + != primary_key_map[attribute['destination_id']]['active'] + ) + or ( + 'code' in attribute + and attribute['code'] + and attribute['code'] + != primary_key_map[attribute['destination_id']]['code'] + ) ): attributes_to_be_updated.append( DestinationAttribute( id=primary_key_map[attribute['destination_id']]['id'], value=attribute['value'], - detail=attribute['detail'] if 'detail' in attribute else None, - active=attribute['active'] if 'active' in attribute else None, - code=" ".join(attribute['code'].split()) if 'code' in attribute and attribute['code'] else None, - updated_at=datetime.now() + detail=( + attribute['detail'] if 'detail' in attribute else None + ), + active=( + attribute['active'] if 'active' in attribute else None + ), + code=( + ' '.join(attribute['code'].split()) + if 'code' in attribute and attribute['code'] + else None + ), + updated_at=datetime.now(), ) ) if attribute_disable_callback_path and attributes_to_disable: - import_string(attribute_disable_callback_path)(workspace_id, attributes_to_disable, is_import_to_fyle_enabled) + import_string(attribute_disable_callback_path)( + workspace_id, attributes_to_disable, is_import_to_fyle_enabled + ) if attributes_to_be_created: - DestinationAttribute.objects.bulk_create(attributes_to_be_created, batch_size=50) + DestinationAttribute.objects.bulk_create( + attributes_to_be_created, batch_size=50 + ) if attributes_to_be_updated: DestinationAttribute.objects.bulk_update( - attributes_to_be_updated, fields=['detail', 'value', 'active', 'updated_at', 'code'], batch_size=50) + attributes_to_be_updated, + fields=['detail', 'value', 'active', 'updated_at', 'code'], + batch_size=50, + ) class ExpenseField(models.Model): - """ + ''' Expense Fields - """ + ''' id = models.AutoField(primary_key=True) attribute_type = models.CharField(max_length=255, help_text='Attribute Type') source_field_id = models.IntegerField(help_text='Field ID') - workspace = models.ForeignKey(Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') + workspace = models.ForeignKey( + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' + ) is_enabled = models.BooleanField(default=False, help_text='Is the field Enabled') - created_at = models.DateTimeField(auto_now_add=True, help_text='Created at datetime') + 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') class Meta: @@ -450,45 +593,70 @@ class Meta: unique_together = ('attribute_type', 'workspace_id') @staticmethod - def create_or_update_expense_fields(attributes: List[Dict], fields_included: List[str], workspace_id): - """ + def create_or_update_expense_fields( + attributes: List[Dict], fields_included: List[str], workspace_id + ): + ''' Update or Create Expense Fields - """ + ''' # Looping over Expense Field Values expense_fields = None for expense_field in attributes: - if expense_field['field_name'] in fields_included or expense_field['type'] == 'DEPENDENT_SELECT': + if ( + expense_field['field_name'] in fields_included + or expense_field['type'] == 'DEPENDENT_SELECT' + ): expense_fields, _ = ExpenseField.objects.update_or_create( - attribute_type=expense_field['field_name'].replace(' ', '_').upper(), + attribute_type=expense_field['field_name'] + .replace(' ', '_') + .upper(), workspace_id=workspace_id, defaults={ 'source_field_id': expense_field['id'], - 'is_enabled': expense_field['is_enabled'] if 'is_enabled' in expense_field else False - } + 'is_enabled': ( + expense_field['is_enabled'] + if 'is_enabled' in expense_field + else False + ), + }, ) return expense_fields class MappingSetting(models.Model): - """ + ''' Mapping Settings - """ + ''' + id = models.AutoField(primary_key=True) source_field = models.CharField(max_length=255, help_text='Source mapping field') - destination_field = models.CharField(max_length=255, help_text='Destination mapping field') - import_to_fyle = models.BooleanField(default=False, help_text='Import to Fyle or not') + destination_field = models.CharField( + max_length=255, help_text='Destination mapping field' + ) + import_to_fyle = models.BooleanField( + default=False, help_text='Import to Fyle or not' + ) is_custom = models.BooleanField(default=False, help_text='Custom Field or not') - source_placeholder = models.TextField(help_text='placeholder of source field', null=True) + source_placeholder = models.TextField( + help_text='placeholder of source field', null=True + ) expense_field = models.ForeignKey( - ExpenseField, on_delete=models.PROTECT, help_text='Reference to Expense Field model', - related_name='expense_fields', null=True + ExpenseField, + on_delete=models.PROTECT, + help_text='Reference to Expense Field model', + related_name='expense_fields', + null=True, ) workspace = models.ForeignKey( - Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model', - related_name='mapping_settings' + Workspace, + on_delete=models.PROTECT, + help_text='Reference to Workspace model', + related_name='mapping_settings', + ) + created_at = models.DateTimeField( + auto_now_add=True, help_text='Created at datetime' ) - 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') class Meta: @@ -497,9 +665,9 @@ class Meta: @staticmethod def bulk_upsert_mapping_setting(settings: List[Dict], workspace_id: int): - """ + ''' Bulk update or create mapping setting - """ + ''' validate_mapping_settings(settings) mapping_settings = [] @@ -510,11 +678,19 @@ def bulk_upsert_mapping_setting(settings: List[Dict], workspace_id: int): source_field=setting['source_field'], workspace_id=workspace_id, destination_field=setting['destination_field'], - expense_field_id=setting['parent_field'] if 'parent_field' in setting else None, + expense_field_id=( + setting['parent_field'] if 'parent_field' in setting else None + ), defaults={ - '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 - } + '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 + ), + }, ) mapping_settings.append(mapping_setting) @@ -522,16 +698,25 @@ def bulk_upsert_mapping_setting(settings: List[Dict], workspace_id: int): class Mapping(models.Model): - """ + ''' Mappings - """ + ''' + id = models.AutoField(primary_key=True) source_type = models.CharField(max_length=255, help_text='Fyle Enum') destination_type = models.CharField(max_length=255, help_text='Destination Enum') - source = models.ForeignKey(ExpenseAttribute, on_delete=models.PROTECT, related_name='mapping') - destination = models.ForeignKey(DestinationAttribute, on_delete=models.PROTECT, related_name='mapping') - workspace = models.ForeignKey(Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') - created_at = models.DateTimeField(auto_now_add=True, help_text='Created at datetime') + source = models.ForeignKey( + ExpenseAttribute, on_delete=models.PROTECT, related_name='mapping' + ) + destination = models.ForeignKey( + DestinationAttribute, on_delete=models.PROTECT, related_name='mapping' + ) + workspace = models.ForeignKey( + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' + ) + 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') class Meta: @@ -539,29 +724,46 @@ class Meta: db_table = 'mappings' @staticmethod - def create_or_update_mapping(source_type: str, destination_type: str, - source_value: str, destination_value: str, destination_id: str, workspace_id: int): - """ + def create_or_update_mapping( + source_type: str, + destination_type: str, + source_value: str, + destination_value: str, + destination_id: str, + workspace_id: int, + ): + ''' Bulk update or create mappings source_type = 'Type of Source attribute, eg. CATEGORY', destination_type = 'Type of Destination attribute, eg. ACCOUNT', source_value = 'Source value to be mapped, eg. category name', destination_value = 'Destination value to be mapped, eg. account name' workspace_id = Unique Workspace id - """ - settings = MappingSetting.objects.filter(source_field=source_type, destination_field=destination_type, - workspace_id=workspace_id).first() + ''' + settings = MappingSetting.objects.filter( + source_field=source_type, + destination_field=destination_type, + workspace_id=workspace_id, + ).first() assert_valid( settings is not None and settings != [], - 'Settings for Destination {0} / Source {1} not found'.format(destination_type, source_type) + 'Settings for Destination {0} / Source {1} not found'.format( + destination_type, source_type + ), ) mapping, _ = Mapping.objects.update_or_create( source_type=source_type, - source=ExpenseAttribute.objects.filter( - attribute_type=source_type, value__iexact=source_value, workspace_id=workspace_id - ).first() if source_value else None, + source=( + ExpenseAttribute.objects.filter( + attribute_type=source_type, + value__iexact=source_value, + workspace_id=workspace_id, + ).first() + if source_value + else None + ), destination_type=destination_type, workspace=Workspace.objects.get(pk=workspace_id), defaults={ @@ -569,16 +771,21 @@ def create_or_update_mapping(source_type: str, destination_type: str, attribute_type=destination_type, value=destination_value, destination_id=destination_id, - workspace_id=workspace_id + workspace_id=workspace_id, ) - } + }, ) return mapping @staticmethod - def bulk_create_mappings(destination_attributes: List[DestinationAttribute], source_type: str, - destination_type: str, workspace_id: int, set_auto_mapped_flag: bool = True): - """ + def bulk_create_mappings( + destination_attributes: List[DestinationAttribute], + source_type: str, + destination_type: str, + workspace_id: int, + set_auto_mapped_flag: bool = True, + ): + ''' Bulk create mappings :param set_auto_mapped_flag: set auto mapped to expense attributes :param destination_type: Destination Type @@ -586,15 +793,18 @@ def bulk_create_mappings(destination_attributes: List[DestinationAttribute], sou :param destination_attributes: Destination Attributes List :param workspace_id: workspace_id :return: mappings list - """ + ''' attribute_value_list = [] for destination_attribute in destination_attributes: attribute_value_list.append(destination_attribute.value) source_attributes: List[ExpenseAttribute] = ExpenseAttribute.objects.filter( - value__in=attribute_value_list, workspace_id=workspace_id, - attribute_type=source_type, mapping__source_id__isnull=True).all() + value__in=attribute_value_list, + workspace_id=workspace_id, + attribute_type=source_type, + mapping__source_id__isnull=True, + ).all() source_value_id_map = {} @@ -609,37 +819,49 @@ def bulk_create_mappings(destination_attributes: List[DestinationAttribute], sou Mapping( source_type=source_type, destination_type=destination_type, - source_id=source_value_id_map[destination_attribute.value.lower()], + source_id=source_value_id_map[ + destination_attribute.value.lower() + ], destination_id=destination_attribute.id, - workspace_id=workspace_id + workspace_id=workspace_id, ) ) return create_mappings_and_update_flag(mapping_batch, set_auto_mapped_flag) @staticmethod - def auto_map_employees(destination_type: str, employee_mapping_preference: str, workspace_id: int): - """ + def auto_map_employees( + destination_type: str, employee_mapping_preference: str, workspace_id: int + ): + ''' Auto map employees :param destination_type: Destination Type of mappings :param employee_mapping_preference: Employee Mapping Preference :param workspace_id: Workspace ID - """ + ''' # Filtering only not mapped destination attributes employee_destination_attributes = DestinationAttribute.objects.filter( - attribute_type=destination_type, workspace_id=workspace_id).all() + attribute_type=destination_type, workspace_id=workspace_id + ).all() destination_id_value_map = {} for destination_employee in employee_destination_attributes: value_to_be_appended = None - if employee_mapping_preference == 'EMAIL' and destination_employee.detail \ - and destination_employee.detail['email']: - value_to_be_appended = destination_employee.detail['email'].replace('*', '') + if ( + employee_mapping_preference == 'EMAIL' + and destination_employee.detail + and destination_employee.detail['email'] + ): + value_to_be_appended = destination_employee.detail['email'].replace( + '*', '' + ) elif employee_mapping_preference in ['NAME', 'EMPLOYEE_CODE']: value_to_be_appended = destination_employee.value.replace('*', '') if value_to_be_appended: - destination_id_value_map[value_to_be_appended.lower()] = destination_employee.id + destination_id_value_map[value_to_be_appended.lower()] = ( + destination_employee.id + ) employee_source_attributes_count = ExpenseAttribute.objects.filter( attribute_type='EMPLOYEE', workspace_id=workspace_id, auto_mapped=False @@ -655,26 +877,33 @@ def auto_map_employees(destination_type: str, employee_mapping_preference: str, employee_source_attributes.extend(paginated_employee_source_attributes) mapping_batch = construct_mapping_payload( - employee_source_attributes, employee_mapping_preference, - destination_id_value_map, destination_type, workspace_id + employee_source_attributes, + employee_mapping_preference, + destination_id_value_map, + destination_type, + workspace_id, ) create_mappings_and_update_flag(mapping_batch) @staticmethod - def auto_map_ccc_employees(destination_type: str, default_ccc_account_id: str, workspace_id: int): - """ + def auto_map_ccc_employees( + destination_type: str, default_ccc_account_id: str, workspace_id: int + ): + ''' Auto map ccc employees :param destination_type: Destination Type of mappings :param default_ccc_account_id: Default CCC Account :param workspace_id: Workspace ID - """ + ''' employee_source_attributes = ExpenseAttribute.objects.filter( attribute_type='EMPLOYEE', workspace_id=workspace_id ).all() default_destination_attribute = DestinationAttribute.objects.filter( - destination_id=default_ccc_account_id, workspace_id=workspace_id, attribute_type=destination_type + destination_id=default_ccc_account_id, + workspace_id=workspace_id, + attribute_type=destination_type, ).first() existing_source_ids = get_existing_source_ids(destination_type, workspace_id) @@ -689,7 +918,7 @@ def auto_map_ccc_employees(destination_type: str, default_ccc_account_id: str, w destination_type=destination_type, source_id=source_employee.id, destination_id=default_destination_attribute.id, - workspace_id=workspace_id + workspace_id=workspace_id, ) ) @@ -697,20 +926,41 @@ def auto_map_ccc_employees(destination_type: str, default_ccc_account_id: str, w class EmployeeMapping(models.Model): - """ + ''' Employee Mappings - """ + ''' + id = models.AutoField(primary_key=True) source_employee = models.ForeignKey( - ExpenseAttribute, on_delete=models.PROTECT, related_name='employeemapping', unique=True) + ExpenseAttribute, + on_delete=models.PROTECT, + related_name='employeemapping', + unique=True, + ) destination_employee = models.ForeignKey( - DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_employee') + DestinationAttribute, + on_delete=models.PROTECT, + null=True, + related_name='destination_employee', + ) destination_vendor = models.ForeignKey( - DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_vendor') + DestinationAttribute, + on_delete=models.PROTECT, + null=True, + related_name='destination_vendor', + ) destination_card_account = models.ForeignKey( - DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_card_account') - workspace = models.ForeignKey(Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') - created_at = models.DateTimeField(auto_now_add=True, help_text='Created at datetime') + DestinationAttribute, + on_delete=models.PROTECT, + null=True, + related_name='destination_card_account', + ) + workspace = models.ForeignKey( + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' + ) + 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') class Meta: @@ -718,10 +968,13 @@ class Meta: @staticmethod def create_or_update_employee_mapping( - source_employee_id: int, workspace: Workspace, - destination_employee_id: int = None, destination_vendor_id: int = None, - destination_card_account_id: int = None): - """ + source_employee_id: int, + workspace: Workspace, + destination_employee_id: int = None, + destination_vendor_id: int = None, + destination_card_account_id: int = None, + ): + ''' Create single instance of employee mappings :param source_employee_id: employee expense attribute id :param workspace: workspace instance @@ -729,32 +982,47 @@ def create_or_update_employee_mapping( :param destination_vendor_id: vendor destination attribute id :param destination_card_account_id: card destination attribute id :return: - """ + ''' employee_mapping, _ = EmployeeMapping.objects.update_or_create( source_employee_id=source_employee_id, workspace=workspace, defaults={ 'destination_employee_id': destination_employee_id, 'destination_vendor_id': destination_vendor_id, - 'destination_card_account_id': destination_card_account_id - } + 'destination_card_account_id': destination_card_account_id, + }, ) return employee_mapping class CategoryMapping(models.Model): - """ + ''' Category Mappings - """ + ''' + id = models.AutoField(primary_key=True) - source_category = models.ForeignKey(ExpenseAttribute, on_delete=models.PROTECT, related_name='categorymapping') + source_category = models.ForeignKey( + ExpenseAttribute, on_delete=models.PROTECT, related_name='categorymapping' + ) destination_account = models.ForeignKey( - DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_account') + DestinationAttribute, + on_delete=models.PROTECT, + null=True, + related_name='destination_account', + ) destination_expense_head = models.ForeignKey( - DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_expense_head') - workspace = models.ForeignKey(Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') - created_at = models.DateTimeField(auto_now_add=True, help_text='Created at datetime') + DestinationAttribute, + on_delete=models.PROTECT, + null=True, + related_name='destination_expense_head', + ) + workspace = models.ForeignKey( + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' + ) + 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') class Meta: @@ -762,34 +1030,41 @@ class Meta: @staticmethod def create_or_update_category_mapping( - source_category_id: int, workspace: Workspace, - destination_account_id: int = None, destination_expense_head_id: int = None): - """ + source_category_id: int, + workspace: Workspace, + destination_account_id: int = None, + destination_expense_head_id: int = None, + ): + ''' Create single instance of category mappings :param source_category_id: category expense attribute id :param workspace: workspace instance :param destination_account_id: category destination attribute id :param destination_expense_head_id: expense head destination attribute id :return: - """ + ''' category_mapping, _ = CategoryMapping.objects.update_or_create( source_category_id=source_category_id, workspace=workspace, defaults={ 'destination_account_id': destination_account_id, - 'destination_expense_head_id': destination_expense_head_id - } + 'destination_expense_head_id': destination_expense_head_id, + }, ) return category_mapping @staticmethod - def bulk_create_mappings(destination_attributes: List[DestinationAttribute], - destination_type: str, workspace_id: int, set_auto_mapped_flag: bool = True): - """ + def bulk_create_mappings( + destination_attributes: List[DestinationAttribute], + destination_type: str, + workspace_id: int, + set_auto_mapped_flag: bool = True, + ): + ''' Create the bulk mapping :param destination_attributes: Destination Attributes List with category mapping as null - """ + ''' attribute_value_list = [] for destination_attribute in destination_attributes: @@ -800,11 +1075,13 @@ def bulk_create_mappings(destination_attributes: List[DestinationAttribute], workspace_id=workspace_id, attribute_type='CATEGORY', value__in=attribute_value_list, - categorymapping__source_category__isnull=True + categorymapping__source_category__isnull=True, ).values('id', 'value') - source_attributes_id_map = {source_attribute['value'].lower(): source_attribute['id'] \ - for source_attribute in source_attributes} + source_attributes_id_map = { + source_attribute['value'].lower(): source_attribute['id'] + for source_attribute in source_attributes + } mapping_creation_batch = [] @@ -812,49 +1089,67 @@ def bulk_create_mappings(destination_attributes: List[DestinationAttribute], if destination_attribute.value.lower() in source_attributes_id_map: destination = {} if destination_type in ('EXPENSE_TYPE', 'EXPENSE_CATEGORY'): - destination['destination_expense_head_id'] = destination_attribute.id + destination['destination_expense_head_id'] = ( + destination_attribute.id + ) elif destination_type == 'ACCOUNT': destination['destination_account_id'] = destination_attribute.id mapping_creation_batch.append( CategoryMapping( - source_category_id=source_attributes_id_map[destination_attribute.value.lower()], + source_category_id=source_attributes_id_map[ + destination_attribute.value.lower() + ], workspace_id=workspace_id, **destination ) ) - return create_mappings_and_update_flag(mapping_creation_batch, set_auto_mapped_flag, model_type=CategoryMapping) + return create_mappings_and_update_flag( + mapping_creation_batch, set_auto_mapped_flag, model_type=CategoryMapping + ) @staticmethod def bulk_create_ccc_category_mappings(workspace_id: int): - """ + ''' Create Category Mappings for CCC Expenses :param workspace_id: Workspace ID - """ + ''' category_mappings = CategoryMapping.objects.filter( - workspace_id=workspace_id, - destination_account__isnull=True + workspace_id=workspace_id, destination_account__isnull=True ).all() destination_account_internal_ids = [] for category_mapping in category_mappings: - if category_mapping.destination_expense_head.detail and \ - 'gl_account_no' in category_mapping.destination_expense_head.detail and \ - category_mapping.destination_expense_head.detail['gl_account_no']: - destination_account_internal_ids.append(category_mapping.destination_expense_head.detail['gl_account_no']) + if ( + category_mapping.destination_expense_head.detail + and 'gl_account_no' in category_mapping.destination_expense_head.detail + and category_mapping.destination_expense_head.detail['gl_account_no'] + ): + destination_account_internal_ids.append( + category_mapping.destination_expense_head.detail['gl_account_no'] + ) - elif category_mapping.destination_expense_head.detail and \ - 'account_internal_id' in category_mapping.destination_expense_head.detail and \ - category_mapping.destination_expense_head.detail['account_internal_id']: - destination_account_internal_ids.append(category_mapping.destination_expense_head.detail['account_internal_id']) + elif ( + category_mapping.destination_expense_head.detail + and 'account_internal_id' + in category_mapping.destination_expense_head.detail + and category_mapping.destination_expense_head.detail[ + 'account_internal_id' + ] + ): + destination_account_internal_ids.append( + category_mapping.destination_expense_head.detail[ + 'account_internal_id' + ] + ) # Retreiving accounts for creating ccc mapping destination_attributes = DestinationAttribute.objects.filter( workspace_id=workspace_id, attribute_type='ACCOUNT', - destination_id__in=destination_account_internal_ids + destination_id__in=destination_account_internal_ids, ).values('id', 'destination_id') destination_id_pk_map = {} @@ -866,21 +1161,40 @@ def bulk_create_ccc_category_mappings(workspace_id: int): for category_mapping in category_mappings: ccc_account_id = None - if category_mapping.destination_expense_head.detail and \ - 'gl_account_no' in category_mapping.destination_expense_head.detail and\ - category_mapping.destination_expense_head.detail['gl_account_no'].lower() in destination_id_pk_map: - ccc_account_id = destination_id_pk_map[category_mapping.destination_expense_head.detail['gl_account_no'].lower()] - - elif category_mapping.destination_expense_head.detail and \ - 'account_internal_id' in category_mapping.destination_expense_head.detail and \ - category_mapping.destination_expense_head.detail['account_internal_id'].lower() in destination_id_pk_map: - ccc_account_id = destination_id_pk_map[category_mapping.destination_expense_head.detail['account_internal_id'].lower()] + if ( + category_mapping.destination_expense_head.detail + and 'gl_account_no' in category_mapping.destination_expense_head.detail + and category_mapping.destination_expense_head.detail[ + 'gl_account_no' + ].lower() + in destination_id_pk_map + ): + ccc_account_id = destination_id_pk_map[ + category_mapping.destination_expense_head.detail[ + 'gl_account_no' + ].lower() + ] + + elif ( + category_mapping.destination_expense_head.detail + and 'account_internal_id' + in category_mapping.destination_expense_head.detail + and category_mapping.destination_expense_head.detail[ + 'account_internal_id' + ].lower() + in destination_id_pk_map + ): + ccc_account_id = destination_id_pk_map[ + category_mapping.destination_expense_head.detail[ + 'account_internal_id' + ].lower() + ] mapping_updation_batch.append( CategoryMapping( id=category_mapping.id, source_category_id=category_mapping.source_category.id, - destination_account_id=ccc_account_id + destination_account_id=ccc_account_id, ) ) @@ -892,18 +1206,18 @@ def bulk_create_ccc_category_mappings(workspace_id: int): class AutoAddCreateUpdateInfoManager(models.Manager): def update_or_create(self, defaults=None, **kwargs): - """ + ''' Overrides the default update_or_create to handle 'user' keyword argument. - """ - user = kwargs.pop("user", None) + ''' + user = kwargs.pop('user', None) defaults = defaults or {} - if user and hasattr(user, "email"): - defaults["updated_by"] = user.email + if user and hasattr(user, 'email'): + defaults['updated_by'] = user.email instance, created = super().update_or_create(defaults=defaults, **kwargs) - if created and user and hasattr(user, "email"): + if created and user and hasattr(user, 'email'): instance.created_by = user.email instance.save(user=user) @@ -911,22 +1225,22 @@ def update_or_create(self, defaults=None, **kwargs): class AutoAddCreateUpdateInfoMixin(models.Model): - """ + ''' Mixin to automatically set created_by and updated_by fields. Stores only the user's email. - """ + ''' created_by = models.CharField( max_length=255, null=True, blank=True, - help_text="Email of the user who created this record", + help_text='Email of the user who created this record', ) updated_by = models.CharField( max_length=255, null=True, blank=True, - help_text="Email of the user who last updated this record", + help_text='Email of the user who last updated this record', ) objects = AutoAddCreateUpdateInfoManager() @@ -935,12 +1249,12 @@ class Meta: abstract = True def save(self, *args, **kwargs): - """ + ''' Override the save method to set created_by and updated_by fields. Expects a 'user' keyword argument containing the user instance. - """ - user = kwargs.pop("user", None) - if user and hasattr(user, "email"): + ''' + user = kwargs.pop('user', None) + if user and hasattr(user, 'email'): if not self.pk: self.created_by = user.email self.updated_by = user.email From 642da0258acb022ad58add48d30c5a39423d09b6 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 18:46:55 +0530 Subject: [PATCH 05/16] correct linting --- fyle_accounting_mappings/models.py | 874 +++++++++++------------------ 1 file changed, 318 insertions(+), 556 deletions(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 4ff5c28..eaaeee3 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -10,7 +10,7 @@ from .utils import assert_valid -workspace_models = importlib.import_module('apps.workspaces.models') +workspace_models = importlib.import_module("apps.workspaces.models") Workspace = workspace_models.Workspace @@ -20,23 +20,19 @@ def validate_mapping_settings(mappings_settings: List[Dict]): row = 0 for mappings_setting in mappings_settings: - if ('source_field' not in mappings_setting) and ( - not mappings_setting['source_field'] - ): - bulk_errors.append( - {'row': row, 'value': None, 'message': 'source field cannot be empty'} - ) - - if ('destination_field' not in mappings_setting) and ( - not mappings_setting['destination_field'] - ): - bulk_errors.append( - { - 'row': row, - 'value': None, - 'message': 'destination field cannot be empty', - } - ) + if ('source_field' not in mappings_setting) and (not mappings_setting['source_field']): + bulk_errors.append({ + 'row': row, + 'value': None, + 'message': 'source field cannot be empty' + }) + + if ('destination_field' not in mappings_setting) and (not mappings_setting['destination_field']): + bulk_errors.append({ + 'row': row, + 'value': None, + 'message': 'destination field cannot be empty' + }) row = row + 1 @@ -44,12 +40,11 @@ def validate_mapping_settings(mappings_settings: List[Dict]): raise BulkError('Errors while creating settings', bulk_errors) -def create_mappings_and_update_flag( - mapping_batch: list, set_auto_mapped_flag: bool = True, **kwargs -): +def create_mappings_and_update_flag(mapping_batch: list, set_auto_mapped_flag: bool = True, **kwargs): model_type = kwargs['model_type'] if 'model_type' in kwargs else Mapping if model_type == CategoryMapping: - mappings = CategoryMapping.objects.bulk_create(mapping_batch, batch_size=50) + mappings = CategoryMapping.objects.bulk_create( + mapping_batch, batch_size=50) else: mappings = Mapping.objects.bulk_create(mapping_batch, batch_size=50) @@ -59,31 +54,22 @@ def create_mappings_and_update_flag( for mapping in mappings: expense_attributes_to_be_updated.append( ExpenseAttribute( - id=( - mapping.source_category.id - if model_type == CategoryMapping - else mapping.source.id - ), - auto_mapped=True, + id=mapping.source_category.id if model_type == CategoryMapping else mapping.source.id, + auto_mapped=True ) ) if expense_attributes_to_be_updated: ExpenseAttribute.objects.bulk_update( - expense_attributes_to_be_updated, fields=['auto_mapped'], batch_size=50 - ) + expense_attributes_to_be_updated, fields=['auto_mapped'], batch_size=50) return mappings -def construct_mapping_payload( - employee_source_attributes: list, - employee_mapping_preference: str, - destination_id_value_map: dict, - destination_type: str, - workspace_id: int, -): - existing_source_ids = get_existing_source_ids(destination_type, workspace_id) +def construct_mapping_payload(employee_source_attributes: list, employee_mapping_preference: str, + destination_id_value_map: dict, destination_type: str, workspace_id: int): + existing_source_ids = get_existing_source_ids( + destination_type, workspace_id) mapping_batch = [] for source_attribute in employee_source_attributes: @@ -105,7 +91,7 @@ def construct_mapping_payload( destination_type=destination_type, source_id=source_attribute.id, destination_id=destination_id, - workspace_id=workspace_id, + workspace_id=workspace_id ) ) @@ -114,9 +100,7 @@ def construct_mapping_payload( def get_existing_source_ids(destination_type: str, workspace_id: int): existing_mappings = Mapping.objects.filter( - source_type='EMPLOYEE', - destination_type=destination_type, - workspace_id=workspace_id, + source_type='EMPLOYEE', destination_type=destination_type, workspace_id=workspace_id ).all() existing_source_ids = [] @@ -128,48 +112,43 @@ def get_existing_source_ids(destination_type: str, workspace_id: int): class ExpenseAttributesDeletionCache(models.Model): id = models.AutoField(primary_key=True) - category_ids = ArrayField(default=[], base_field=models.CharField(max_length=255)) - project_ids = ArrayField(default=[], base_field=models.CharField(max_length=255)) + category_ids = ArrayField( + default=[], base_field=models.CharField(max_length=255)) + project_ids = ArrayField( + default=[], base_field=models.CharField(max_length=255)) workspace = models.OneToOneField( - Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' - ) + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') class Meta: db_table = 'expense_attributes_deletion_cache' class ExpenseAttribute(models.Model): - ''' + """ Fyle Expense Attributes - ''' - + """ id = models.AutoField(primary_key=True) attribute_type = models.CharField( - max_length=255, help_text='Type of expense attribute' - ) + max_length=255, help_text='Type of expense attribute') display_name = models.CharField( - max_length=255, help_text='Display name of expense attribute' - ) - value = models.CharField(max_length=1000, help_text='Value of expense attribute') + max_length=255, help_text='Display name of expense attribute') + value = models.CharField( + max_length=1000, help_text='Value of expense attribute') source_id = models.CharField(max_length=255, help_text='Fyle ID') workspace = models.ForeignKey( - Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' - ) + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') auto_mapped = models.BooleanField( - default=False, help_text='Indicates whether the field is auto mapped or not' - ) - auto_created = models.BooleanField( - default=False, - help_text='Indicates whether the field is auto created by the integration', - ) + default=False, help_text='Indicates whether the field is auto mapped or not') + auto_created = models.BooleanField(default=False, + help_text='Indicates whether the field is auto created by the integration') active = models.BooleanField( - null=True, help_text='Indicates whether the fields is active or not' - ) - detail = JSONField(help_text='Detailed expense attributes payload', null=True) + null=True, help_text='Indicates whether the fields is active or not') + detail = JSONField( + help_text='Detailed expense attributes payload', null=True) 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') + auto_now_add=True, help_text='Created at datetime') + updated_at = models.DateTimeField( + auto_now=True, help_text='Updated at datetime') class Meta: db_table = 'expense_attributes' @@ -177,9 +156,9 @@ class Meta: @staticmethod def create_or_update_expense_attribute(attribute: Dict, workspace_id): - ''' + """ Get or create expense attribute - ''' + """ expense_attribute, _ = ExpenseAttribute.objects.update_or_create( attribute_type=attribute['attribute_type'], value=attribute['value'], @@ -188,21 +167,20 @@ def create_or_update_expense_attribute(attribute: Dict, workspace_id): 'active': attribute['active'] if 'active' in attribute else None, 'source_id': attribute['source_id'], 'display_name': attribute['display_name'], - 'detail': attribute['detail'] if 'detail' in attribute else None, - }, + 'detail': attribute['detail'] if 'detail' in attribute else None + } ) return expense_attribute @staticmethod def bulk_update_deleted_expense_attributes(attribute_type: str, workspace_id: int): - ''' + """ Bulk update deleted expense attributes :param attribute_type: Attribute type :param workspace_id: Workspace Id - ''' + """ expense_attributes_deletion_cache = ExpenseAttributesDeletionCache.objects.get( - workspace_id=workspace_id - ) + workspace_id=workspace_id) attributes_to_be_updated = [] if attribute_type == 'CATEGORY': @@ -221,23 +199,20 @@ def bulk_update_deleted_expense_attributes(attribute_type: str, workspace_id: in for attribute in deleted_attributes: attributes_to_be_updated.append( ExpenseAttribute( - id=attribute.id, active=False, updated_at=datetime.now() + id=attribute.id, + active=False, + updated_at=datetime.now() ) ) if attributes_to_be_updated: ExpenseAttribute.objects.bulk_update( - attributes_to_be_updated, fields=['active', 'updated_at'], batch_size=50 - ) + attributes_to_be_updated, fields=['active', 'updated_at'], batch_size=50) @staticmethod def bulk_create_or_update_expense_attributes( - attributes: List[Dict], - attribute_type: str, - workspace_id: int, - update: bool = False, - ): - ''' + attributes: List[Dict], attribute_type: str, workspace_id: int, update: bool = False): + """ Create Expense Attributes in bulk :param update: Update Pre-existing records or not :param attribute_type: Attribute type @@ -250,14 +225,12 @@ def bulk_create_or_update_expense_attributes( }] :param workspace_id: Workspace Id :return: created / updated attributes - ''' + """ attribute_value_list = [attribute['value'] for attribute in attributes] existing_attributes = ExpenseAttribute.objects.filter( - value__in=attribute_value_list, - attribute_type=attribute_type, - workspace_id=workspace_id, - ).values('id', 'value', 'detail', 'active') + value__in=attribute_value_list, attribute_type=attribute_type, + workspace_id=workspace_id).values('id', 'value', 'detail', 'active') existing_attribute_values = [] @@ -268,7 +241,7 @@ def bulk_create_or_update_expense_attributes( primary_key_map[existing_attribute['value']] = { 'id': existing_attribute['id'], 'detail': existing_attribute['detail'], - 'active': existing_attribute['active'], + 'active': existing_attribute['active'] } attributes_to_be_created = [] @@ -276,10 +249,7 @@ def bulk_create_or_update_expense_attributes( values_appended = [] for attribute in attributes: - if ( - attribute['value'] not in existing_attribute_values - and attribute['value'] not in values_appended - ): + if attribute['value'] not in existing_attribute_values and attribute['value'] not in values_appended: values_appended.append(attribute['value']) attributes_to_be_created.append( ExpenseAttribute( @@ -289,7 +259,7 @@ def bulk_create_or_update_expense_attributes( source_id=attribute['source_id'], detail=attribute['detail'] if 'detail' in attribute else None, workspace_id=workspace_id, - active=attribute['active'] if 'active' in attribute else None, + active=attribute['active'] if 'active' in attribute else None ) ) else: @@ -298,90 +268,70 @@ def bulk_create_or_update_expense_attributes( ExpenseAttribute( id=primary_key_map[attribute['value']]['id'], source_id=attribute['source_id'], - detail=( - attribute['detail'] if 'detail' in attribute else None - ), - active=( - attribute['active'] if 'active' in attribute else None - ), + detail=attribute['detail'] if 'detail' in attribute else None, + active=attribute['active'] if 'active' in attribute else None ) ) if attributes_to_be_created: ExpenseAttribute.objects.bulk_create( - attributes_to_be_created, batch_size=50 - ) + attributes_to_be_created, batch_size=50) if attributes_to_be_updated: ExpenseAttribute.objects.bulk_update( - attributes_to_be_updated, - fields=['source_id', 'detail', 'active'], - batch_size=50, - ) + attributes_to_be_updated, fields=['source_id', 'detail', 'active'], batch_size=50) @staticmethod def get_last_synced_at(attribute_type: str, workspace_id: int): - ''' + """ Get last synced at datetime :param attribute_type: Attribute type :param workspace_id: Workspace Id :return: last_synced_at datetime - ''' - return ( - ExpenseAttribute.objects.filter( - workspace_id=workspace_id, attribute_type=attribute_type - ) - .order_by('-updated_at') - .first() - ) + """ + return ExpenseAttribute.objects.filter( + workspace_id=workspace_id, + attribute_type=attribute_type + ).order_by('-updated_at').first() class DestinationAttribute(models.Model): - ''' + """ Destination Expense Attributes - ''' - + """ id = models.AutoField(primary_key=True) attribute_type = models.CharField( - max_length=255, help_text='Type of expense attribute' - ) + max_length=255, help_text='Type of expense attribute') display_name = models.CharField( - max_length=255, help_text='Display name of attribute' - ) - value = models.CharField(max_length=255, help_text='Value of expense attribute') - destination_id = models.CharField(max_length=255, help_text='Destination ID') + max_length=255, help_text='Display name of attribute') + value = models.CharField( + max_length=255, help_text='Value of expense attribute') + destination_id = models.CharField( + max_length=255, help_text='Destination ID') workspace = models.ForeignKey( - Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' - ) - auto_created = models.BooleanField( - default=False, - help_text='Indicates whether the field is auto created by the integration', - ) + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') + auto_created = models.BooleanField(default=False, + help_text='Indicates whether the field is auto created by the integration') active = models.BooleanField( - null=True, help_text='Indicates whether the fields is active or not' - ) - detail = JSONField(help_text='Detailed destination attributes payload', null=True) + null=True, help_text='Indicates whether the fields is active or not') + detail = JSONField( + help_text='Detailed destination attributes payload', null=True) code = models.CharField( - max_length=255, help_text='Code of the attribute', null=True - ) + max_length=255, help_text='Code of the attribute', null=True) 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') + auto_now_add=True, help_text='Created at datetime') + updated_at = models.DateTimeField( + auto_now=True, help_text='Updated at datetime') class Meta: db_table = 'destination_attributes' - unique_together = ( - 'destination_id', - 'attribute_type', - 'workspace', - 'display_name', - ) + unique_together = ('destination_id', 'attribute_type', + 'workspace', 'display_name') @staticmethod def create_or_update_destination_attribute(attribute: Dict, workspace_id): - ''' + """ get or create destination attributes - ''' + """ destination_attribute, _ = DestinationAttribute.objects.update_or_create( attribute_type=attribute['attribute_type'], destination_id=attribute['destination_id'], @@ -391,26 +341,22 @@ def create_or_update_destination_attribute(attribute: Dict, workspace_id): 'display_name': attribute['display_name'], 'value': attribute['value'], 'detail': attribute['detail'] if 'detail' in attribute else None, - 'code': ( - ' '.join(attribute['code'].split()) - if 'code' in attribute and attribute['code'] - else None - ), - }, + 'code': " ".join(attribute['code'].split()) if 'code' in attribute and attribute['code'] else None + } ) return destination_attribute @staticmethod def bulk_create_or_update_destination_attributes( - attributes: List[Dict], - attribute_type: str, - workspace_id: int, - update: bool = False, - display_name: str = None, - attribute_disable_callback_path: str = None, - is_import_to_fyle_enabled: bool = False, + attributes: List[Dict], + attribute_type: str, + workspace_id: int, + update: bool = False, + display_name: str = None, + attribute_disable_callback_path: str = None, + is_import_to_fyle_enabled: bool = False ): - ''' + """ Create Destination Attributes in bulk :param update: Update Pre-existing records or not :param attribute_type: Attribute type @@ -424,22 +370,20 @@ def bulk_create_or_update_destination_attributes( :param workspace_id: Workspace Id :param attributes_disable_callback_path: API func to call when attribute is to be disabled :return: created / updated attributes - ''' + """ attribute_destination_id_list = [ - attribute['destination_id'] for attribute in attributes - ] + attribute['destination_id'] for attribute in attributes] filters = { 'destination_id__in': attribute_destination_id_list, 'attribute_type': attribute_type, - 'workspace_id': workspace_id, + 'workspace_id': workspace_id } if display_name: filters['display_name'] = display_name - existing_attributes = DestinationAttribute.objects.filter(**filters).values( - 'id', 'value', 'destination_id', 'detail', 'active', 'code' - ) + existing_attributes = DestinationAttribute.objects.filter(**filters)\ + .values('id', 'value', 'destination_id', 'detail', 'active', 'code') existing_attribute_destination_ids = [] @@ -447,14 +391,13 @@ def bulk_create_or_update_destination_attributes( for existing_attribute in existing_attributes: existing_attribute_destination_ids.append( - existing_attribute['destination_id'] - ) + existing_attribute['destination_id']) primary_key_map[existing_attribute['destination_id']] = { 'id': existing_attribute['id'], 'value': existing_attribute['value'], 'detail': existing_attribute['detail'], 'active': existing_attribute['active'], - 'code': existing_attribute['code'], + 'code': existing_attribute['code'] } attributes_to_be_created = [] @@ -463,10 +406,8 @@ def bulk_create_or_update_destination_attributes( destination_ids_appended = [] for attribute in attributes: - if ( - attribute['destination_id'] not in existing_attribute_destination_ids - and attribute['destination_id'] not in destination_ids_appended - ): + if attribute['destination_id'] not in existing_attribute_destination_ids \ + and attribute['destination_id'] not in destination_ids_appended: destination_ids_appended.append(attribute['destination_id']) attributes_to_be_created.append( DestinationAttribute( @@ -477,187 +418,126 @@ def bulk_create_or_update_destination_attributes( detail=attribute['detail'] if 'detail' in attribute else None, workspace_id=workspace_id, active=attribute['active'] if 'active' in attribute else None, - code=( - ' '.join(attribute['code'].split()) - if 'code' in attribute and attribute['code'] - else None - ), + code=" ".join(attribute['code'].split( + )) if 'code' in attribute and attribute['code'] else None ) ) else: - if ( - attribute_disable_callback_path - and is_import_to_fyle_enabled - and ( - ( - attribute['value'] - and primary_key_map[attribute['destination_id']]['value'] - and attribute['value'].lower() - != primary_key_map[attribute['destination_id']][ - 'value' - ].lower() - ) - or ( - 'code' in attribute - and attribute['code'] - and attribute['code'] - != primary_key_map[attribute['destination_id']]['code'] - ) - ) + if attribute_disable_callback_path and is_import_to_fyle_enabled and ( + (attribute['value'] and primary_key_map[attribute['destination_id']]['value'] and attribute['value'].lower( + ) != primary_key_map[attribute['destination_id']]['value'].lower()) + or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) ): attributes_to_disable[attribute['destination_id']] = { 'value': primary_key_map[attribute['destination_id']]['value'], 'updated_value': attribute['value'], 'code': primary_key_map[attribute['destination_id']]['code'], - 'updated_code': attribute['code'], + 'updated_code': attribute['code'] } if update and ( - ( - attribute['value'] - != primary_key_map[attribute['destination_id']]['value'] - ) - or ( - 'detail' in attribute - and attribute['detail'] - != primary_key_map[attribute['destination_id']]['detail'] - ) - or ( - 'active' in attribute - and attribute['active'] - != primary_key_map[attribute['destination_id']]['active'] - ) - or ( - 'code' in attribute - and attribute['code'] - and attribute['code'] - != primary_key_map[attribute['destination_id']]['code'] - ) + (attribute['value'] != + primary_key_map[attribute['destination_id']]['value']) + or ('detail' in attribute and attribute['detail'] != primary_key_map[attribute['destination_id']]['detail']) + or ('active' in attribute and attribute['active'] != primary_key_map[attribute['destination_id']]['active']) + or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) ): attributes_to_be_updated.append( DestinationAttribute( id=primary_key_map[attribute['destination_id']]['id'], value=attribute['value'], - detail=( - attribute['detail'] if 'detail' in attribute else None - ), - active=( - attribute['active'] if 'active' in attribute else None - ), - code=( - ' '.join(attribute['code'].split()) - if 'code' in attribute and attribute['code'] - else None - ), - updated_at=datetime.now(), + detail=attribute['detail'] if 'detail' in attribute else None, + active=attribute['active'] if 'active' in attribute else None, + code=" ".join(attribute['code'].split( + )) if 'code' in attribute and attribute['code'] else None, + updated_at=datetime.now() ) ) if attribute_disable_callback_path and attributes_to_disable: import_string(attribute_disable_callback_path)( - workspace_id, attributes_to_disable, is_import_to_fyle_enabled - ) + workspace_id, attributes_to_disable, is_import_to_fyle_enabled) if attributes_to_be_created: DestinationAttribute.objects.bulk_create( - attributes_to_be_created, batch_size=50 - ) + attributes_to_be_created, batch_size=50) if attributes_to_be_updated: DestinationAttribute.objects.bulk_update( - attributes_to_be_updated, - fields=['detail', 'value', 'active', 'updated_at', 'code'], - batch_size=50, - ) + attributes_to_be_updated, fields=['detail', 'value', 'active', 'updated_at', 'code'], batch_size=50) class ExpenseField(models.Model): - ''' + """ Expense Fields - ''' + """ id = models.AutoField(primary_key=True) - attribute_type = models.CharField(max_length=255, help_text='Attribute Type') + attribute_type = models.CharField( + max_length=255, help_text='Attribute Type') source_field_id = models.IntegerField(help_text='Field ID') workspace = models.ForeignKey( - Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' - ) - is_enabled = models.BooleanField(default=False, help_text='Is the field Enabled') + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') + is_enabled = models.BooleanField( + default=False, help_text='Is the field Enabled') 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') + auto_now_add=True, help_text='Created at datetime') + updated_at = models.DateTimeField( + auto_now=True, help_text='Updated at datetime') class Meta: db_table = 'expense_fields' unique_together = ('attribute_type', 'workspace_id') @staticmethod - def create_or_update_expense_fields( - attributes: List[Dict], fields_included: List[str], workspace_id - ): - ''' + def create_or_update_expense_fields(attributes: List[Dict], fields_included: List[str], workspace_id): + """ Update or Create Expense Fields - ''' + """ # Looping over Expense Field Values expense_fields = None for expense_field in attributes: - if ( - expense_field['field_name'] in fields_included - or expense_field['type'] == 'DEPENDENT_SELECT' - ): + if expense_field['field_name'] in fields_included or expense_field['type'] == 'DEPENDENT_SELECT': expense_fields, _ = ExpenseField.objects.update_or_create( - attribute_type=expense_field['field_name'] - .replace(' ', '_') - .upper(), + attribute_type=expense_field['field_name'].replace( + ' ', '_').upper(), workspace_id=workspace_id, defaults={ 'source_field_id': expense_field['id'], - 'is_enabled': ( - expense_field['is_enabled'] - if 'is_enabled' in expense_field - else False - ), - }, + 'is_enabled': expense_field['is_enabled'] if 'is_enabled' in expense_field else False + } ) return expense_fields class MappingSetting(models.Model): - ''' + """ Mapping Settings - ''' - + """ id = models.AutoField(primary_key=True) - source_field = models.CharField(max_length=255, help_text='Source mapping field') + source_field = models.CharField( + max_length=255, help_text='Source mapping field') destination_field = models.CharField( - max_length=255, help_text='Destination mapping field' - ) + max_length=255, help_text='Destination mapping field') import_to_fyle = models.BooleanField( - default=False, help_text='Import to Fyle or not' - ) - is_custom = models.BooleanField(default=False, help_text='Custom Field or not') + default=False, help_text='Import to Fyle or not') + is_custom = models.BooleanField( + default=False, help_text='Custom Field or not') source_placeholder = models.TextField( - help_text='placeholder of source field', null=True - ) + help_text='placeholder of source field', null=True) expense_field = models.ForeignKey( - ExpenseField, - on_delete=models.PROTECT, - help_text='Reference to Expense Field model', - related_name='expense_fields', - null=True, + ExpenseField, on_delete=models.PROTECT, help_text='Reference to Expense Field model', + related_name='expense_fields', null=True ) workspace = models.ForeignKey( - Workspace, - on_delete=models.PROTECT, - help_text='Reference to Workspace model', - related_name='mapping_settings', + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model', + related_name='mapping_settings' ) 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') + auto_now_add=True, help_text='Created at datetime') + updated_at = models.DateTimeField( + auto_now=True, help_text='Updated at datetime') class Meta: unique_together = ('source_field', 'destination_field', 'workspace') @@ -665,9 +545,9 @@ class Meta: @staticmethod def bulk_upsert_mapping_setting(settings: List[Dict], workspace_id: int): - ''' + """ Bulk update or create mapping setting - ''' + """ validate_mapping_settings(settings) mapping_settings = [] @@ -678,19 +558,11 @@ def bulk_upsert_mapping_setting(settings: List[Dict], workspace_id: int): source_field=setting['source_field'], workspace_id=workspace_id, destination_field=setting['destination_field'], - expense_field_id=( - setting['parent_field'] if 'parent_field' in setting else None - ), + expense_field_id=setting['parent_field'] if 'parent_field' in setting else None, defaults={ - '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 - ), - }, + '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 + } ) mapping_settings.append(mapping_setting) @@ -698,72 +570,54 @@ def bulk_upsert_mapping_setting(settings: List[Dict], workspace_id: int): class Mapping(models.Model): - ''' + """ Mappings - ''' - + """ id = models.AutoField(primary_key=True) source_type = models.CharField(max_length=255, help_text='Fyle Enum') - destination_type = models.CharField(max_length=255, help_text='Destination Enum') + destination_type = models.CharField( + max_length=255, help_text='Destination Enum') source = models.ForeignKey( - ExpenseAttribute, on_delete=models.PROTECT, related_name='mapping' - ) + ExpenseAttribute, on_delete=models.PROTECT, related_name='mapping') destination = models.ForeignKey( - DestinationAttribute, on_delete=models.PROTECT, related_name='mapping' - ) + DestinationAttribute, on_delete=models.PROTECT, related_name='mapping') workspace = models.ForeignKey( - Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' - ) + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') 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') + auto_now_add=True, help_text='Created at datetime') + updated_at = models.DateTimeField( + auto_now=True, help_text='Updated at datetime') class Meta: - unique_together = ('source_type', 'source', 'destination_type', 'workspace') + unique_together = ('source_type', 'source', + 'destination_type', 'workspace') db_table = 'mappings' @staticmethod - def create_or_update_mapping( - source_type: str, - destination_type: str, - source_value: str, - destination_value: str, - destination_id: str, - workspace_id: int, - ): - ''' + def create_or_update_mapping(source_type: str, destination_type: str, + source_value: str, destination_value: str, destination_id: str, workspace_id: int): + """ Bulk update or create mappings source_type = 'Type of Source attribute, eg. CATEGORY', destination_type = 'Type of Destination attribute, eg. ACCOUNT', source_value = 'Source value to be mapped, eg. category name', destination_value = 'Destination value to be mapped, eg. account name' workspace_id = Unique Workspace id - ''' - settings = MappingSetting.objects.filter( - source_field=source_type, - destination_field=destination_type, - workspace_id=workspace_id, - ).first() + """ + settings = MappingSetting.objects.filter(source_field=source_type, destination_field=destination_type, + workspace_id=workspace_id).first() assert_valid( settings is not None and settings != [], 'Settings for Destination {0} / Source {1} not found'.format( - destination_type, source_type - ), + destination_type, source_type) ) mapping, _ = Mapping.objects.update_or_create( source_type=source_type, - source=( - ExpenseAttribute.objects.filter( - attribute_type=source_type, - value__iexact=source_value, - workspace_id=workspace_id, - ).first() - if source_value - else None - ), + source=ExpenseAttribute.objects.filter( + attribute_type=source_type, value__iexact=source_value, workspace_id=workspace_id + ).first() if source_value else None, destination_type=destination_type, workspace=Workspace.objects.get(pk=workspace_id), defaults={ @@ -771,21 +625,16 @@ def create_or_update_mapping( attribute_type=destination_type, value=destination_value, destination_id=destination_id, - workspace_id=workspace_id, + workspace_id=workspace_id ) - }, + } ) return mapping @staticmethod - def bulk_create_mappings( - destination_attributes: List[DestinationAttribute], - source_type: str, - destination_type: str, - workspace_id: int, - set_auto_mapped_flag: bool = True, - ): - ''' + def bulk_create_mappings(destination_attributes: List[DestinationAttribute], source_type: str, + destination_type: str, workspace_id: int, set_auto_mapped_flag: bool = True): + """ Bulk create mappings :param set_auto_mapped_flag: set auto mapped to expense attributes :param destination_type: Destination Type @@ -793,23 +642,21 @@ def bulk_create_mappings( :param destination_attributes: Destination Attributes List :param workspace_id: workspace_id :return: mappings list - ''' + """ attribute_value_list = [] for destination_attribute in destination_attributes: attribute_value_list.append(destination_attribute.value) source_attributes: List[ExpenseAttribute] = ExpenseAttribute.objects.filter( - value__in=attribute_value_list, - workspace_id=workspace_id, - attribute_type=source_type, - mapping__source_id__isnull=True, - ).all() + value__in=attribute_value_list, workspace_id=workspace_id, + attribute_type=source_type, mapping__source_id__isnull=True).all() source_value_id_map = {} for source_attribute in source_attributes: - source_value_id_map[source_attribute.value.lower()] = source_attribute.id + source_value_id_map[source_attribute.value.lower() + ] = source_attribute.id mapping_batch = [] @@ -819,49 +666,41 @@ def bulk_create_mappings( Mapping( source_type=source_type, destination_type=destination_type, - source_id=source_value_id_map[ - destination_attribute.value.lower() - ], + source_id=source_value_id_map[destination_attribute.value.lower( + )], destination_id=destination_attribute.id, - workspace_id=workspace_id, + workspace_id=workspace_id ) ) return create_mappings_and_update_flag(mapping_batch, set_auto_mapped_flag) @staticmethod - def auto_map_employees( - destination_type: str, employee_mapping_preference: str, workspace_id: int - ): - ''' + def auto_map_employees(destination_type: str, employee_mapping_preference: str, workspace_id: int): + """ Auto map employees :param destination_type: Destination Type of mappings :param employee_mapping_preference: Employee Mapping Preference :param workspace_id: Workspace ID - ''' + """ # Filtering only not mapped destination attributes employee_destination_attributes = DestinationAttribute.objects.filter( - attribute_type=destination_type, workspace_id=workspace_id - ).all() + attribute_type=destination_type, workspace_id=workspace_id).all() destination_id_value_map = {} for destination_employee in employee_destination_attributes: value_to_be_appended = None - if ( - employee_mapping_preference == 'EMAIL' - and destination_employee.detail - and destination_employee.detail['email'] - ): + if employee_mapping_preference == 'EMAIL' and destination_employee.detail \ + and destination_employee.detail['email']: value_to_be_appended = destination_employee.detail['email'].replace( - '*', '' - ) + '*', '') elif employee_mapping_preference in ['NAME', 'EMPLOYEE_CODE']: - value_to_be_appended = destination_employee.value.replace('*', '') + value_to_be_appended = destination_employee.value.replace( + '*', '') if value_to_be_appended: - destination_id_value_map[value_to_be_appended.lower()] = ( - destination_employee.id - ) + destination_id_value_map[value_to_be_appended.lower( + )] = destination_employee.id employee_source_attributes_count = ExpenseAttribute.objects.filter( attribute_type='EMPLOYEE', workspace_id=workspace_id, auto_mapped=False @@ -874,39 +713,34 @@ def auto_map_employees( paginated_employee_source_attributes = ExpenseAttribute.objects.filter( attribute_type='EMPLOYEE', workspace_id=workspace_id, auto_mapped=False )[offset:limit] - employee_source_attributes.extend(paginated_employee_source_attributes) + employee_source_attributes.extend( + paginated_employee_source_attributes) mapping_batch = construct_mapping_payload( - employee_source_attributes, - employee_mapping_preference, - destination_id_value_map, - destination_type, - workspace_id, + employee_source_attributes, employee_mapping_preference, + destination_id_value_map, destination_type, workspace_id ) create_mappings_and_update_flag(mapping_batch) @staticmethod - def auto_map_ccc_employees( - destination_type: str, default_ccc_account_id: str, workspace_id: int - ): - ''' + def auto_map_ccc_employees(destination_type: str, default_ccc_account_id: str, workspace_id: int): + """ Auto map ccc employees :param destination_type: Destination Type of mappings :param default_ccc_account_id: Default CCC Account :param workspace_id: Workspace ID - ''' + """ employee_source_attributes = ExpenseAttribute.objects.filter( attribute_type='EMPLOYEE', workspace_id=workspace_id ).all() default_destination_attribute = DestinationAttribute.objects.filter( - destination_id=default_ccc_account_id, - workspace_id=workspace_id, - attribute_type=destination_type, + destination_id=default_ccc_account_id, workspace_id=workspace_id, attribute_type=destination_type ).first() - existing_source_ids = get_existing_source_ids(destination_type, workspace_id) + existing_source_ids = get_existing_source_ids( + destination_type, workspace_id) mapping_batch = [] for source_employee in employee_source_attributes: @@ -918,7 +752,7 @@ def auto_map_ccc_employees( destination_type=destination_type, source_id=source_employee.id, destination_id=default_destination_attribute.id, - workspace_id=workspace_id, + workspace_id=workspace_id ) ) @@ -926,55 +760,34 @@ def auto_map_ccc_employees( class EmployeeMapping(models.Model): - ''' + """ Employee Mappings - ''' - + """ id = models.AutoField(primary_key=True) source_employee = models.ForeignKey( - ExpenseAttribute, - on_delete=models.PROTECT, - related_name='employeemapping', - unique=True, - ) + ExpenseAttribute, on_delete=models.PROTECT, related_name='employeemapping', unique=True) destination_employee = models.ForeignKey( - DestinationAttribute, - on_delete=models.PROTECT, - null=True, - related_name='destination_employee', - ) + DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_employee') destination_vendor = models.ForeignKey( - DestinationAttribute, - on_delete=models.PROTECT, - null=True, - related_name='destination_vendor', - ) + DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_vendor') destination_card_account = models.ForeignKey( - DestinationAttribute, - on_delete=models.PROTECT, - null=True, - related_name='destination_card_account', - ) + DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_card_account') workspace = models.ForeignKey( - Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' - ) + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') 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') + auto_now_add=True, help_text='Created at datetime') + updated_at = models.DateTimeField( + auto_now=True, help_text='Updated at datetime') class Meta: db_table = 'employee_mappings' @staticmethod def create_or_update_employee_mapping( - source_employee_id: int, - workspace: Workspace, - destination_employee_id: int = None, - destination_vendor_id: int = None, - destination_card_account_id: int = None, - ): - ''' + source_employee_id: int, workspace: Workspace, + destination_employee_id: int = None, destination_vendor_id: int = None, + destination_card_account_id: int = None): + """ Create single instance of employee mappings :param source_employee_id: employee expense attribute id :param workspace: workspace instance @@ -982,89 +795,71 @@ def create_or_update_employee_mapping( :param destination_vendor_id: vendor destination attribute id :param destination_card_account_id: card destination attribute id :return: - ''' + """ employee_mapping, _ = EmployeeMapping.objects.update_or_create( source_employee_id=source_employee_id, workspace=workspace, defaults={ 'destination_employee_id': destination_employee_id, 'destination_vendor_id': destination_vendor_id, - 'destination_card_account_id': destination_card_account_id, - }, + 'destination_card_account_id': destination_card_account_id + } ) return employee_mapping class CategoryMapping(models.Model): - ''' + """ Category Mappings - ''' - + """ id = models.AutoField(primary_key=True) source_category = models.ForeignKey( - ExpenseAttribute, on_delete=models.PROTECT, related_name='categorymapping' - ) + ExpenseAttribute, on_delete=models.PROTECT, related_name='categorymapping') destination_account = models.ForeignKey( - DestinationAttribute, - on_delete=models.PROTECT, - null=True, - related_name='destination_account', - ) + DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_account') destination_expense_head = models.ForeignKey( - DestinationAttribute, - on_delete=models.PROTECT, - null=True, - related_name='destination_expense_head', - ) + DestinationAttribute, on_delete=models.PROTECT, null=True, related_name='destination_expense_head') workspace = models.ForeignKey( - Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model' - ) + Workspace, on_delete=models.PROTECT, help_text='Reference to Workspace model') 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') + auto_now_add=True, help_text='Created at datetime') + updated_at = models.DateTimeField( + auto_now=True, help_text='Updated at datetime') class Meta: db_table = 'category_mappings' @staticmethod def create_or_update_category_mapping( - source_category_id: int, - workspace: Workspace, - destination_account_id: int = None, - destination_expense_head_id: int = None, - ): - ''' + source_category_id: int, workspace: Workspace, + destination_account_id: int = None, destination_expense_head_id: int = None): + """ Create single instance of category mappings :param source_category_id: category expense attribute id :param workspace: workspace instance :param destination_account_id: category destination attribute id :param destination_expense_head_id: expense head destination attribute id :return: - ''' + """ category_mapping, _ = CategoryMapping.objects.update_or_create( source_category_id=source_category_id, workspace=workspace, defaults={ 'destination_account_id': destination_account_id, - 'destination_expense_head_id': destination_expense_head_id, - }, + 'destination_expense_head_id': destination_expense_head_id + } ) return category_mapping @staticmethod - def bulk_create_mappings( - destination_attributes: List[DestinationAttribute], - destination_type: str, - workspace_id: int, - set_auto_mapped_flag: bool = True, - ): - ''' + def bulk_create_mappings(destination_attributes: List[DestinationAttribute], + destination_type: str, workspace_id: int, set_auto_mapped_flag: bool = True): + """ Create the bulk mapping :param destination_attributes: Destination Attributes List with category mapping as null - ''' + """ attribute_value_list = [] for destination_attribute in destination_attributes: @@ -1075,13 +870,11 @@ def bulk_create_mappings( workspace_id=workspace_id, attribute_type='CATEGORY', value__in=attribute_value_list, - categorymapping__source_category__isnull=True, + categorymapping__source_category__isnull=True ).values('id', 'value') - source_attributes_id_map = { - source_attribute['value'].lower(): source_attribute['id'] - for source_attribute in source_attributes - } + source_attributes_id_map = {source_attribute['value'].lower(): source_attribute['id'] + for source_attribute in source_attributes} mapping_creation_batch = [] @@ -1089,112 +882,81 @@ def bulk_create_mappings( if destination_attribute.value.lower() in source_attributes_id_map: destination = {} if destination_type in ('EXPENSE_TYPE', 'EXPENSE_CATEGORY'): - destination['destination_expense_head_id'] = ( - destination_attribute.id - ) + destination['destination_expense_head_id'] = destination_attribute.id elif destination_type == 'ACCOUNT': destination['destination_account_id'] = destination_attribute.id mapping_creation_batch.append( CategoryMapping( - source_category_id=source_attributes_id_map[ - destination_attribute.value.lower() - ], + source_category_id=source_attributes_id_map[destination_attribute.value.lower( + )], workspace_id=workspace_id, **destination ) ) - return create_mappings_and_update_flag( - mapping_creation_batch, set_auto_mapped_flag, model_type=CategoryMapping - ) + return create_mappings_and_update_flag(mapping_creation_batch, set_auto_mapped_flag, model_type=CategoryMapping) @staticmethod def bulk_create_ccc_category_mappings(workspace_id: int): - ''' + """ Create Category Mappings for CCC Expenses :param workspace_id: Workspace ID - ''' + """ category_mappings = CategoryMapping.objects.filter( - workspace_id=workspace_id, destination_account__isnull=True + workspace_id=workspace_id, + destination_account__isnull=True ).all() destination_account_internal_ids = [] for category_mapping in category_mappings: - if ( - category_mapping.destination_expense_head.detail - and 'gl_account_no' in category_mapping.destination_expense_head.detail - and category_mapping.destination_expense_head.detail['gl_account_no'] - ): + if category_mapping.destination_expense_head.detail and \ + 'gl_account_no' in category_mapping.destination_expense_head.detail and \ + category_mapping.destination_expense_head.detail['gl_account_no']: destination_account_internal_ids.append( - category_mapping.destination_expense_head.detail['gl_account_no'] - ) + category_mapping.destination_expense_head.detail['gl_account_no']) - elif ( - category_mapping.destination_expense_head.detail - and 'account_internal_id' - in category_mapping.destination_expense_head.detail - and category_mapping.destination_expense_head.detail[ - 'account_internal_id' - ] - ): + elif category_mapping.destination_expense_head.detail and \ + 'account_internal_id' in category_mapping.destination_expense_head.detail and \ + category_mapping.destination_expense_head.detail['account_internal_id']: destination_account_internal_ids.append( - category_mapping.destination_expense_head.detail[ - 'account_internal_id' - ] - ) + category_mapping.destination_expense_head.detail['account_internal_id']) # Retreiving accounts for creating ccc mapping destination_attributes = DestinationAttribute.objects.filter( workspace_id=workspace_id, attribute_type='ACCOUNT', - destination_id__in=destination_account_internal_ids, + destination_id__in=destination_account_internal_ids ).values('id', 'destination_id') destination_id_pk_map = {} for attribute in destination_attributes: - destination_id_pk_map[attribute['destination_id'].lower()] = attribute['id'] + destination_id_pk_map[attribute['destination_id'].lower( + )] = attribute['id'] mapping_updation_batch = [] for category_mapping in category_mappings: ccc_account_id = None - if ( - category_mapping.destination_expense_head.detail - and 'gl_account_no' in category_mapping.destination_expense_head.detail - and category_mapping.destination_expense_head.detail[ - 'gl_account_no' - ].lower() - in destination_id_pk_map - ): - ccc_account_id = destination_id_pk_map[ - category_mapping.destination_expense_head.detail[ - 'gl_account_no' - ].lower() - ] - - elif ( - category_mapping.destination_expense_head.detail - and 'account_internal_id' - in category_mapping.destination_expense_head.detail - and category_mapping.destination_expense_head.detail[ - 'account_internal_id' - ].lower() - in destination_id_pk_map - ): - ccc_account_id = destination_id_pk_map[ - category_mapping.destination_expense_head.detail[ - 'account_internal_id' - ].lower() - ] + if category_mapping.destination_expense_head.detail and \ + 'gl_account_no' in category_mapping.destination_expense_head.detail and\ + category_mapping.destination_expense_head.detail['gl_account_no'].lower() in destination_id_pk_map: + ccc_account_id = destination_id_pk_map[category_mapping.destination_expense_head.detail['gl_account_no'].lower( + )] + + elif category_mapping.destination_expense_head.detail and \ + 'account_internal_id' in category_mapping.destination_expense_head.detail and \ + category_mapping.destination_expense_head.detail['account_internal_id'].lower() in destination_id_pk_map: + ccc_account_id = destination_id_pk_map[category_mapping.destination_expense_head.detail['account_internal_id'].lower( + )] mapping_updation_batch.append( CategoryMapping( id=category_mapping.id, source_category_id=category_mapping.source_category.id, - destination_account_id=ccc_account_id, + destination_account_id=ccc_account_id ) ) @@ -1206,18 +968,18 @@ def bulk_create_ccc_category_mappings(workspace_id: int): class AutoAddCreateUpdateInfoManager(models.Manager): def update_or_create(self, defaults=None, **kwargs): - ''' + """ Overrides the default update_or_create to handle 'user' keyword argument. - ''' - user = kwargs.pop('user', None) + """ + user = kwargs.pop("user", None) defaults = defaults or {} - if user and hasattr(user, 'email'): - defaults['updated_by'] = user.email + if user and hasattr(user, "email"): + defaults["updated_by"] = user.email instance, created = super().update_or_create(defaults=defaults, **kwargs) - if created and user and hasattr(user, 'email'): + if created and user and hasattr(user, "email"): instance.created_by = user.email instance.save(user=user) @@ -1225,22 +987,22 @@ def update_or_create(self, defaults=None, **kwargs): class AutoAddCreateUpdateInfoMixin(models.Model): - ''' + """ Mixin to automatically set created_by and updated_by fields. Stores only the user's email. - ''' + """ created_by = models.CharField( max_length=255, null=True, blank=True, - help_text='Email of the user who created this record', + help_text="Email of the user who created this record", ) updated_by = models.CharField( max_length=255, null=True, blank=True, - help_text='Email of the user who last updated this record', + help_text="Email of the user who last updated this record", ) objects = AutoAddCreateUpdateInfoManager() @@ -1249,12 +1011,12 @@ class Meta: abstract = True def save(self, *args, **kwargs): - ''' + """ Override the save method to set created_by and updated_by fields. Expects a 'user' keyword argument containing the user instance. - ''' - user = kwargs.pop('user', None) - if user and hasattr(user, 'email'): + """ + user = kwargs.pop("user", None) + if user and hasattr(user, "email"): if not self.pk: self.created_by = user.email self.updated_by = user.email From b7a49f913b0e91be500d31ae83816df662269797 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 19:57:53 +0530 Subject: [PATCH 06/16] fixing lint --- fyle_accounting_mappings/models.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index eaaeee3..624f02b 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -424,14 +424,15 @@ def bulk_create_or_update_destination_attributes( ) else: if attribute_disable_callback_path and is_import_to_fyle_enabled and ( - (attribute['value'] and primary_key_map[attribute['destination_id']]['value'] and attribute['value'].lower( - ) != primary_key_map[attribute['destination_id']]['value'].lower()) - or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) + (attribute['value'] and primary_key_map[attribute['destination_id']]['value'] and + attribute['value'].lower() != primary_key_map[attribute['destination_id']]['value'].lower()) or + ('code' in attribute and attribute['code'] and + attribute['code'] != primary_key_map[attribute['destination_id']]['code']) ): attributes_to_disable[attribute['destination_id']] = { - 'value': primary_key_map[attribute['destination_id']]['value'], + 'value': primary_key_map['destination_id']['value'], 'updated_value': attribute['value'], - 'code': primary_key_map[attribute['destination_id']]['code'], + 'code': primary_key_map['destination_id']['code'], 'updated_code': attribute['code'] } @@ -456,7 +457,10 @@ def bulk_create_or_update_destination_attributes( if attribute_disable_callback_path and attributes_to_disable: import_string(attribute_disable_callback_path)( - workspace_id, attributes_to_disable, is_import_to_fyle_enabled) + workspace_id, + attributes_to_disable, + is_import_to_fyle_enabled + ) if attributes_to_be_created: DestinationAttribute.objects.bulk_create( From 5b3d2f355dfd17f697626315db9e6df8b5065a83 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 20:13:44 +0530 Subject: [PATCH 07/16] pylint resolving --- .pylintrc | 4 ++-- fyle_accounting_mappings/models.py | 9 +++++---- fyle_accounting_mappings/urls.py | 3 ++- fyle_accounting_mappings/views.py | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.pylintrc b/.pylintrc index 32d2b1e..d2a482d 100644 --- a/.pylintrc +++ b/.pylintrc @@ -342,7 +342,7 @@ indent-string=' ' max-line-length=135 # Maximum number of lines in a module. -max-module-lines=1000 +max-module-lines=1200 # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. @@ -559,7 +559,7 @@ max-attributes=7 max-bool-expr=6 # Maximum number of branch for function / method body. -max-branches=13 +max-branches=15 # Maximum number of locals for function / method body. max-locals=20 diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 624f02b..c06e1f4 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -425,9 +425,9 @@ def bulk_create_or_update_destination_attributes( else: if attribute_disable_callback_path and is_import_to_fyle_enabled and ( (attribute['value'] and primary_key_map[attribute['destination_id']]['value'] and - attribute['value'].lower() != primary_key_map[attribute['destination_id']]['value'].lower()) or + attribute['value'].lower() != primary_key_map[attribute['destination_id']]['value'].lower()) or ('code' in attribute and attribute['code'] and - attribute['code'] != primary_key_map[attribute['destination_id']]['code']) + attribute['code'] != primary_key_map[attribute['destination_id']]['code']) ): attributes_to_disable[attribute['destination_id']] = { 'value': primary_key_map['destination_id']['value'], @@ -441,7 +441,8 @@ def bulk_create_or_update_destination_attributes( primary_key_map[attribute['destination_id']]['value']) or ('detail' in attribute and attribute['detail'] != primary_key_map[attribute['destination_id']]['detail']) or ('active' in attribute and attribute['active'] != primary_key_map[attribute['destination_id']]['active']) - or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) + or ('code' in attribute and attribute['code'] and + attribute['code'] != primary_key_map[attribute['destination_id']]['code']) ): attributes_to_be_updated.append( DestinationAttribute( @@ -729,7 +730,7 @@ def auto_map_employees(destination_type: str, employee_mapping_preference: str, @staticmethod def auto_map_ccc_employees(destination_type: str, default_ccc_account_id: str, workspace_id: int): - """ + """̆̆̆̆̆̆̆̆̆̆̆ Auto map ccc employees :param destination_type: Destination Type of mappings :param default_ccc_account_id: Default CCC Account diff --git a/fyle_accounting_mappings/urls.py b/fyle_accounting_mappings/urls.py index 97d3a5a..58c1f10 100644 --- a/fyle_accounting_mappings/urls.py +++ b/fyle_accounting_mappings/urls.py @@ -45,5 +45,6 @@ path('expense_fields/', ExpenseFieldView.as_view()), path('destination_attributes/', DestinationAttributesView.as_view()), path('fyle_fields/', FyleFieldsView.as_view()), - path('paginated_destination_attributes/', PaginatedDestinationAttributesView.as_view(), name='paginated_destination_attributes_view'), + path('paginated_destination_attributes/', + PaginatedDestinationAttributesView.as_view(), name='paginated_destination_attributes_view'), ] diff --git a/fyle_accounting_mappings/views.py b/fyle_accounting_mappings/views.py index 7dbce9e..abc2cd4 100644 --- a/fyle_accounting_mappings/views.py +++ b/fyle_accounting_mappings/views.py @@ -247,7 +247,7 @@ def get(self, request, *args, **kwargs): if source_type == 'CATEGORY': activity_attribute_count = ExpenseAttribute.objects.filter( attribute_type='CATEGORY', value='Activity', workspace_id=self.kwargs['workspace_id'], active=True).count() - + if app_name in ('NetSuite', 'INTACCT', 'Sage 300 CRE', 'Dynamics 365 Business Central'): activity_mapping = CategoryMapping.objects.filter( source_category__value='Activity', workspace_id=self.kwargs['workspace_id']).first() From 5f05f27a9731fa44c7d2e540371a0136aa787799 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 20:26:59 +0530 Subject: [PATCH 08/16] still resolving lint --- fyle_accounting_mappings/models.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index c06e1f4..26574e9 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -1,5 +1,5 @@ import importlib -from typing import List, Dict +from typing import Iterable, List, Dict from datetime import datetime from django.utils.module_loading import import_string from django.db import models, transaction @@ -423,27 +423,30 @@ def bulk_create_or_update_destination_attributes( ) ) else: - if attribute_disable_callback_path and is_import_to_fyle_enabled and ( + condition = ( (attribute['value'] and primary_key_map[attribute['destination_id']]['value'] and attribute['value'].lower() != primary_key_map[attribute['destination_id']]['value'].lower()) or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) - ): + ) + if attribute_disable_callback_path and is_import_to_fyle_enabled and condition: attributes_to_disable[attribute['destination_id']] = { 'value': primary_key_map['destination_id']['value'], 'updated_value': attribute['value'], 'code': primary_key_map['destination_id']['code'], 'updated_code': attribute['code'] } - - if update and ( + + condition = ( (attribute['value'] != primary_key_map[attribute['destination_id']]['value']) or ('detail' in attribute and attribute['detail'] != primary_key_map[attribute['destination_id']]['detail']) or ('active' in attribute and attribute['active'] != primary_key_map[attribute['destination_id']]['active']) or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) - ): + ) + + if update and condition: attributes_to_be_updated.append( DestinationAttribute( id=primary_key_map[attribute['destination_id']]['id'], @@ -1015,7 +1018,7 @@ class AutoAddCreateUpdateInfoMixin(models.Model): class Meta: abstract = True - def save(self, *args, **kwargs): + def save(self, force_insert: bool = False, force_update: bool = False, using: str | None = None, update_fields: Iterable[str] | None = None, **kwargs,) -> None: """ Override the save method to set created_by and updated_by fields. Expects a 'user' keyword argument containing the user instance. @@ -1025,4 +1028,9 @@ def save(self, *args, **kwargs): if not self.pk: self.created_by = user.email self.updated_by = user.email - super().save(*args, **kwargs) + super().save( + force_insert=force_insert, + force_update=force_update, + using=using, + update_fields=update_fields, + ) From a644d94d12649e60aeb84c85811ec48d3718b397 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 20:32:16 +0530 Subject: [PATCH 09/16] again resolving pylint --- fyle_accounting_mappings/models.py | 15 ++++++++------- fyle_accounting_mappings/urls.py | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 26574e9..0783962 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -436,15 +436,15 @@ def bulk_create_or_update_destination_attributes( 'code': primary_key_map['destination_id']['code'], 'updated_code': attribute['code'] } - + condition = ( - (attribute['value'] != + (attribute['value'] != primary_key_map[attribute['destination_id']]['value']) - or ('detail' in attribute and attribute['detail'] != primary_key_map[attribute['destination_id']]['detail']) - or ('active' in attribute and attribute['active'] != primary_key_map[attribute['destination_id']]['active']) - or ('code' in attribute and attribute['code'] and + or ('detail' in attribute and attribute['detail'] != primary_key_map[attribute['destination_id']]['detail']) + or ('active' in attribute and attribute['active'] != primary_key_map[attribute['destination_id']]['active']) + or ('code' in attribute and attribute['code'] and attribute['code'] != primary_key_map[attribute['destination_id']]['code']) - ) + ) if update and condition: attributes_to_be_updated.append( @@ -1018,7 +1018,8 @@ class AutoAddCreateUpdateInfoMixin(models.Model): class Meta: abstract = True - def save(self, force_insert: bool = False, force_update: bool = False, using: str | None = None, update_fields: Iterable[str] | None = None, **kwargs,) -> None: + def save(self, force_insert: bool = False, force_update: bool = False, using: str | None=None, + update_fields: Iterable[str] | None=None, **kwargs,) -> None: """ Override the save method to set created_by and updated_by fields. Expects a 'user' keyword argument containing the user instance. diff --git a/fyle_accounting_mappings/urls.py b/fyle_accounting_mappings/urls.py index 58c1f10..b8566b0 100644 --- a/fyle_accounting_mappings/urls.py +++ b/fyle_accounting_mappings/urls.py @@ -45,6 +45,6 @@ path('expense_fields/', ExpenseFieldView.as_view()), path('destination_attributes/', DestinationAttributesView.as_view()), path('fyle_fields/', FyleFieldsView.as_view()), - path('paginated_destination_attributes/', + path('paginated_destination_attributes/', PaginatedDestinationAttributesView.as_view(), name='paginated_destination_attributes_view'), ] From 04c306b6aee508d4b630f362e400e69a5d8f2e61 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 20:35:15 +0530 Subject: [PATCH 10/16] ye again resolving pylint --- fyle_accounting_mappings/models.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 0783962..829d683 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -436,14 +436,13 @@ def bulk_create_or_update_destination_attributes( 'code': primary_key_map['destination_id']['code'], 'updated_code': attribute['code'] } - + condition = ( - (attribute['value'] != - primary_key_map[attribute['destination_id']]['value']) + (attribute['value'] != primary_key_map[attribute['destination_id']]['value']) or ('detail' in attribute and attribute['detail'] != primary_key_map[attribute['destination_id']]['detail']) or ('active' in attribute and attribute['active'] != primary_key_map[attribute['destination_id']]['active']) or ('code' in attribute and attribute['code'] and - attribute['code'] != primary_key_map[attribute['destination_id']]['code']) + attribute['code'] != primary_key_map[attribute['destination_id']]['code']) ) if update and condition: From ee3a81eb6873146ec9656359a118a052010d1c02 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 20:39:40 +0530 Subject: [PATCH 11/16] final resolving --- fyle_accounting_mappings/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 829d683..23f215d 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -1018,7 +1018,7 @@ class Meta: abstract = True def save(self, force_insert: bool = False, force_update: bool = False, using: str | None=None, - update_fields: Iterable[str] | None=None, **kwargs,) -> None: + update_fields: Iterable[str] | None=None, **kwargs) -> None: """ Override the save method to set created_by and updated_by fields. Expects a 'user' keyword argument containing the user instance. From 17331c6388d4ea7aab4de30e1f85f904ac090f5a Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 20:48:09 +0530 Subject: [PATCH 12/16] ignoring save method override warning --- .pylintrc | 3 ++- fyle_accounting_mappings/models.py | 14 ++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/.pylintrc b/.pylintrc index d2a482d..83a7380 100644 --- a/.pylintrc +++ b/.pylintrc @@ -156,7 +156,8 @@ disable=print-statement, too-many-arguments, too-many-locals, too-few-public-methods, - super-with-arguments + super-with-arguments, + arguments-differ # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 23f215d..61137ce 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -1017,20 +1017,14 @@ class AutoAddCreateUpdateInfoMixin(models.Model): class Meta: abstract = True - def save(self, force_insert: bool = False, force_update: bool = False, using: str | None=None, - update_fields: Iterable[str] | None=None, **kwargs) -> None: + def save(self, *args, **kwargs): """ Override the save method to set created_by and updated_by fields. Expects a 'user' keyword argument containing the user instance. """ - user = kwargs.pop("user", None) - if user and hasattr(user, "email"): + user = kwargs.pop('user', None) + if user and hasattr(user, 'email'): if not self.pk: self.created_by = user.email self.updated_by = user.email - super().save( - force_insert=force_insert, - force_update=force_update, - using=using, - update_fields=update_fields, - ) + super().save(*args, **kwargs) From 3230db5293148404213aa6444efbd0e428baa5f9 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Tue, 24 Dec 2024 20:50:47 +0530 Subject: [PATCH 13/16] remove unused imports --- fyle_accounting_mappings/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 61137ce..5ee74bf 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -1,5 +1,5 @@ import importlib -from typing import Iterable, List, Dict +from typing import List, Dict from datetime import datetime from django.utils.module_loading import import_string from django.db import models, transaction From eed0ebd77c9d4b847de5cdafcd7e5bc8e72f2d60 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Thu, 26 Dec 2024 13:56:20 +0530 Subject: [PATCH 14/16] Feat: Resolve Import Error --- fyle_accounting_mappings/mixins.py | 58 ++++++++++++++++++++++++++++++ fyle_accounting_mappings/models.py | 56 ----------------------------- 2 files changed, 58 insertions(+), 56 deletions(-) create mode 100644 fyle_accounting_mappings/mixins.py diff --git a/fyle_accounting_mappings/mixins.py b/fyle_accounting_mappings/mixins.py new file mode 100644 index 0000000..11bd794 --- /dev/null +++ b/fyle_accounting_mappings/mixins.py @@ -0,0 +1,58 @@ +from django.db import models + + +class AutoAddCreateUpdateInfoManager(models.Manager): + def update_or_create(self, defaults=None, **kwargs): + """ + Overrides the default update_or_create to handle 'user' keyword argument. + """ + user = kwargs.pop("user", None) + defaults = defaults or {} + + if user and hasattr(user, "email"): + defaults["updated_by"] = user.email + + instance, created = super().update_or_create(defaults=defaults, **kwargs) + + if created and user and hasattr(user, "email"): + instance.created_by = user.email + instance.save(user=user) + + return instance, created + + +class AutoAddCreateUpdateInfoMixin(models.Model): + """ + Mixin to automatically set created_by and updated_by fields. + Stores only the user's email. + """ + + created_by = models.CharField( + max_length=255, + null=True, + blank=True, + help_text="Email of the user who created this record", + ) + updated_by = models.CharField( + max_length=255, + null=True, + blank=True, + help_text="Email of the user who last updated this record", + ) + + objects = AutoAddCreateUpdateInfoManager() + + class Meta: + abstract = True + + def save(self, *args, **kwargs): + """ + Override the save method to set created_by and updated_by fields. + Expects a 'user' keyword argument containing the user instance. + """ + user = kwargs.pop('user', None) + if user and hasattr(user, 'email'): + if not self.pk: + self.created_by = user.email + self.updated_by = user.email + super().save(*args, **kwargs) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 5ee74bf..4bc56ba 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -972,59 +972,3 @@ def bulk_create_ccc_category_mappings(workspace_id: int): mapping_updation_batch, fields=['destination_account'], batch_size=50 ) - -class AutoAddCreateUpdateInfoManager(models.Manager): - def update_or_create(self, defaults=None, **kwargs): - """ - Overrides the default update_or_create to handle 'user' keyword argument. - """ - user = kwargs.pop("user", None) - defaults = defaults or {} - - if user and hasattr(user, "email"): - defaults["updated_by"] = user.email - - instance, created = super().update_or_create(defaults=defaults, **kwargs) - - if created and user and hasattr(user, "email"): - instance.created_by = user.email - instance.save(user=user) - - return instance, created - - -class AutoAddCreateUpdateInfoMixin(models.Model): - """ - Mixin to automatically set created_by and updated_by fields. - Stores only the user's email. - """ - - created_by = models.CharField( - max_length=255, - null=True, - blank=True, - help_text="Email of the user who created this record", - ) - updated_by = models.CharField( - max_length=255, - null=True, - blank=True, - help_text="Email of the user who last updated this record", - ) - - objects = AutoAddCreateUpdateInfoManager() - - class Meta: - abstract = True - - def save(self, *args, **kwargs): - """ - Override the save method to set created_by and updated_by fields. - Expects a 'user' keyword argument containing the user instance. - """ - user = kwargs.pop('user', None) - if user and hasattr(user, 'email'): - if not self.pk: - self.created_by = user.email - self.updated_by = user.email - super().save(*args, **kwargs) From ee40b04d1c57f4a6b7e460f36352aacef2f5957a Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Thu, 26 Dec 2024 13:57:32 +0530 Subject: [PATCH 15/16] bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 03509bd..eb94159 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name='fyle-accounting-mappings', - version='1.36.0', + version='1.36.1', author='Shwetabh Kumar', author_email='shwetabh.kumar@fyle.in', description='Django application to store the fyle accounting mappings in a generic manner', From 0121d642c11791f243df7b0c60f3979bcf1d6c63 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Thu, 26 Dec 2024 13:59:42 +0530 Subject: [PATCH 16/16] resolve lint --- fyle_accounting_mappings/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fyle_accounting_mappings/models.py b/fyle_accounting_mappings/models.py index 4bc56ba..da5c23a 100644 --- a/fyle_accounting_mappings/models.py +++ b/fyle_accounting_mappings/models.py @@ -971,4 +971,3 @@ def bulk_create_ccc_category_mappings(workspace_id: int): CategoryMapping.objects.bulk_update( mapping_updation_batch, fields=['destination_account'], batch_size=50 ) -