From 93db1322dc0ebb8b6b77a8b8d99ff713005deafa Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Tue, 1 Oct 2024 17:33:00 +0500 Subject: [PATCH 1/9] [ISSUE-3694] Add ContactExclusionSet sync and model --- djautotask/admin.py | 2 +- djautotask/api.py | 4 ++++ .../0118_contract_contract_exclusion_set_id.py | 18 ++++++++++++++++++ djautotask/models.py | 4 +++- djautotask/sync.py | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 djautotask/migrations/0118_contract_contract_exclusion_set_id.py diff --git a/djautotask/admin.py b/djautotask/admin.py index 88ba7bf..f46a39c 100644 --- a/djautotask/admin.py +++ b/djautotask/admin.py @@ -305,7 +305,7 @@ class ResourceServiceDeskRoleAdmin(admin.ModelAdmin): @admin.register(models.Contract) class ContractAdmin(admin.ModelAdmin): - list_display = ('id', 'name', 'number', 'account', 'status_name') + list_display = ('id', 'name', 'number', 'account', 'status_name', 'contract_exclusion_set_id') search_fields = ('id', 'name', 'number') list_filter = ('status',) diff --git a/djautotask/api.py b/djautotask/api.py index a64826c..3b62b38 100644 --- a/djautotask/api.py +++ b/djautotask/api.py @@ -721,6 +721,10 @@ class ContractsAPIClient(AutotaskAPIClient): API = 'Contracts' +class ContractsExcludedWorkTypesAPIClient(AutotaskAPIClient): + API = 'ContractExclusionSetExcludedWorkTypes' + + class AccountPhysicalLocationsAPIClient(AutotaskAPIClient): API = 'CompanyLocations' diff --git a/djautotask/migrations/0118_contract_contract_exclusion_set_id.py b/djautotask/migrations/0118_contract_contract_exclusion_set_id.py new file mode 100644 index 0000000..8b14fdf --- /dev/null +++ b/djautotask/migrations/0118_contract_contract_exclusion_set_id.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2024-09-27 18:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('djautotask', '0117_alter_tasknote_task_alter_ticketnote_ticket'), + ] + + operations = [ + migrations.AddField( + model_name='contract', + name='contract_exclusion_set_id', + field=models.IntegerField(blank=True, null=True), + ), + ] diff --git a/djautotask/models.py b/djautotask/models.py index 5843b31..8008fcc 100644 --- a/djautotask/models.py +++ b/djautotask/models.py @@ -948,10 +948,12 @@ class Contract(models.Model): number = models.CharField(blank=True, null=True, max_length=50) status = models.CharField( max_length=20, blank=True, null=True, choices=STATUS_CHOICES) - account = models.ForeignKey( 'Account', blank=True, null=True, on_delete=models.SET_NULL ) + contract_exclusion_set_id = models.IntegerField( + blank=True, null=True + ) class Meta: ordering = ('name',) diff --git a/djautotask/sync.py b/djautotask/sync.py index 4c93870..18917d5 100644 --- a/djautotask/sync.py +++ b/djautotask/sync.py @@ -1812,6 +1812,7 @@ def _assign_field_data(self, instance, object_data): instance.name = object_data.get('contractName') instance.number = object_data.get('contractNumber') instance.status = str(object_data.get('status')) + instance.contract_exclusion_set_id = object_data.get('contractExclusionSetID') self.set_relations(instance, object_data) @@ -2003,6 +2004,19 @@ def active_ids(self): return active_ids +class ContractExcludedWorkTypesSynchronizer(Synchronizer): + client_class = api.ContractsExcludedWorkTypesAPIClient + + def __init__(self, contract_exclusion_set_id=None, *args, **kwargs): + super().__init__(*args, **kwargs) + self.contract_exclusion_set_id = contract_exclusion_set_id + + if contract_exclusion_set_id: + self.client.add_condition( + A(op='eq', field="contractExclusionSetID", value=self.contract_exclusion_set_id) + ) + + class NoteTypeSynchronizer(PicklistSynchronizer): # Ticket note types are including task note types, and there are other # note types currently not used. e.g. project note types From cd790beeaf5353913e7232612507ad917318e838 Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Fri, 4 Oct 2024 19:05:36 +0500 Subject: [PATCH 2/9] Bump version & add ExcludedRoles Sync --- djautotask/api.py | 4 ++++ djautotask/sync.py | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/djautotask/api.py b/djautotask/api.py index 3b62b38..d635be8 100644 --- a/djautotask/api.py +++ b/djautotask/api.py @@ -725,6 +725,10 @@ class ContractsExcludedWorkTypesAPIClient(AutotaskAPIClient): API = 'ContractExclusionSetExcludedWorkTypes' +class ContractsExcludedRolesAPIClient(AutotaskAPIClient): + API = 'ContractExclusionSetExcludedRoles' + + class AccountPhysicalLocationsAPIClient(AutotaskAPIClient): API = 'CompanyLocations' diff --git a/djautotask/sync.py b/djautotask/sync.py index 18917d5..210cef4 100644 --- a/djautotask/sync.py +++ b/djautotask/sync.py @@ -2017,6 +2017,19 @@ def __init__(self, contract_exclusion_set_id=None, *args, **kwargs): ) +class ContractExcludedRolesSynchronizer(Synchronizer): + client_class = api.ContractsExcludedRolesAPIClient + + def __init__(self, contract_exclusion_set_id=None, *args, **kwargs): + super().__init__(*args, **kwargs) + self.contract_exclusion_set_id = contract_exclusion_set_id + + if contract_exclusion_set_id: + self.client.add_condition( + A(op='eq', field="contractExclusionSetID", value=self.contract_exclusion_set_id) + ) + + class NoteTypeSynchronizer(PicklistSynchronizer): # Ticket note types are including task note types, and there are other # note types currently not used. e.g. project note types From 70d0bc76ac59726f2a68571d299d8c6c24598cc3 Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Fri, 11 Oct 2024 16:04:54 +0500 Subject: [PATCH 3/9] Update ContractExcluded Models and Syncronizer --- djautotask/admin.py | 8 +++ djautotask/management/commands/atsync.py | 10 ++++ ...dworktype_contractexcludedrole_and_more.py | 53 ++++++++++++++++ djautotask/models.py | 34 +++++++++++ djautotask/sync.py | 60 ++++++++++++++----- 5 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 djautotask/migrations/0119_contractexcludedworktype_contractexcludedrole_and_more.py diff --git a/djautotask/admin.py b/djautotask/admin.py index f46a39c..0e3264b 100644 --- a/djautotask/admin.py +++ b/djautotask/admin.py @@ -402,3 +402,11 @@ class ProjectNoteTypeAdmin(admin.ModelAdmin): @admin.register(models.CompanyAlert) class CompanyAlertsAdmin(admin.ModelAdmin): list_display = ('id', 'alert_text', 'alert_type', 'account') +@admin.register(models.ContractExcludedWorkType) +class ContractExcludedWorkTypeAdmin(admin.ModelAdmin): + list_display = ('id', 'contract_exclusion_set_id') + + +@admin.register(models.ContractExcludedRole) +class ContractExcludedRoleAdmin(admin.ModelAdmin): + list_display = ('id', 'contract_exclusion_set_id') diff --git a/djautotask/management/commands/atsync.py b/djautotask/management/commands/atsync.py index ccbfbe9..07369a7 100644 --- a/djautotask/management/commands/atsync.py +++ b/djautotask/management/commands/atsync.py @@ -134,6 +134,16 @@ def __init__(self, *args, **kwargs): ('task_predecessor', sync.TaskPredecessorSynchronizer, _('Task Predecessor')), ('contact', sync.ContactSynchronizer, _('Contact')), + ( + 'contract_excluded_worktype', + sync.ContractExcludedWorkTypesSynchronizer, + _('Contract Excluded Work Type') + ), + ( + 'contract_excluded_role', + sync.ContractExcludedRolesSynchronizer, + _('Contract Excluded Role') + ), ) self.synchronizer_map = OrderedDict() for name, synchronizer, obj_name in synchronizers: diff --git a/djautotask/migrations/0119_contractexcludedworktype_contractexcludedrole_and_more.py b/djautotask/migrations/0119_contractexcludedworktype_contractexcludedrole_and_more.py new file mode 100644 index 0000000..d83a13a --- /dev/null +++ b/djautotask/migrations/0119_contractexcludedworktype_contractexcludedrole_and_more.py @@ -0,0 +1,53 @@ +# Generated by Django 4.2.16 on 2024-10-10 19:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('djautotask', '0118_contract_contract_exclusion_set_id'), + ] + + operations = [ + migrations.CreateModel( + name='ContractExcludedWorkType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('contract_exclusion_set_id', models.IntegerField(blank=True, null=True)), + ('excluded_work_types', models.ManyToManyField(related_name='excluded_in_contracts', to='djautotask.billingcode')), + ], + ), + migrations.CreateModel( + name='ContractExcludedRole', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('contract_exclusion_set_id', models.IntegerField(blank=True, null=True)), + ('excluded_roles', models.ManyToManyField(related_name='excluded_in_contracts', to='djautotask.role')), + ], + ), + migrations.CreateModel( + name='ContractExcludedWorkTypeTracker', + fields=[ + ], + options={ + 'db_table': 'djautotask_contract_excluded_worktype', + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('djautotask.contractexcludedworktype',), + ), + migrations.CreateModel( + name='ContractExcludeRoleTracker', + fields=[ + ], + options={ + 'db_table': 'djautotask_contract_excluded_role', + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('djautotask.contractexcludedrole',), + ), + ] diff --git a/djautotask/models.py b/djautotask/models.py index 8008fcc..33bb557 100644 --- a/djautotask/models.py +++ b/djautotask/models.py @@ -962,6 +962,24 @@ def __str__(self): return self.name +class ContractExcludedWorkType(models.Model): + contract_exclusion_set_id = models.IntegerField( + blank=True, null=True + ) + excluded_work_types = models.ManyToManyField( + 'BillingCode', related_name='excluded_in_contracts' + ) + + +class ContractExcludedRole(models.Model): + contract_exclusion_set_id = models.IntegerField( + blank=True, null=True + ) + excluded_roles = models.ManyToManyField( + 'Role', related_name='excluded_in_contracts' + ) + + class ServiceCall(TimeStampedModel): description = models.TextField(blank=True, null=True, max_length=2000) duration = models.DecimalField( @@ -1465,6 +1483,22 @@ class Meta: db_table = 'djautotask_contract' +class ContractExcludedWorkTypeTracker(ContractExcludedWorkType): + tracker = FieldTracker() + + class Meta: + proxy = True + db_table = 'djautotask_contract_excluded_worktype' + + +class ContractExcludeRoleTracker(ContractExcludedRole): + tracker = FieldTracker() + + class Meta: + proxy = True + db_table = 'djautotask_contract_excluded_role' + + class ServiceCallTracker(ServiceCall): tracker = FieldTracker() diff --git a/djautotask/sync.py b/djautotask/sync.py index 210cef4..2fe9cb1 100644 --- a/djautotask/sync.py +++ b/djautotask/sync.py @@ -2004,30 +2004,60 @@ def active_ids(self): return active_ids -class ContractExcludedWorkTypesSynchronizer(Synchronizer): +class ContractExcludedWorkTypesSynchronizer(BatchQueryMixin, Synchronizer): client_class = api.ContractsExcludedWorkTypesAPIClient + model_class = models.ContractExcludedWorkTypeTracker + condition_field_name = 'contractExclusionSetID' + lookup_key = 'contractExclusionSetID' + last_updated_field = None - def __init__(self, contract_exclusion_set_id=None, *args, **kwargs): - super().__init__(*args, **kwargs) - self.contract_exclusion_set_id = contract_exclusion_set_id + def _assign_field_data(self, instance, object_data): + instance.contract_exclusion_set_id = object_data[self.lookup_key] + try: + exclusion_set = models.ContractExcludedWorkType.objects.get(pk=instance.id) + except models.ContractExcludedWorkType.DoesNotExist: + instance.id = object_data[self.lookup_key] + instance.save() + + work_type = models.BillingCode.objects.filter(id=object_data['excludedWorkTypeID'], use_type=1).first() + instance.excluded_work_types.add(work_type) - if contract_exclusion_set_id: - self.client.add_condition( - A(op='eq', field="contractExclusionSetID", value=self.contract_exclusion_set_id) - ) + return instance + + @property + def active_ids(self): + active_ids = models.Contract.objects.exclude(contract_exclusion_set_id=None).values_list( + 'contract_exclusion_set_id', flat=True + ).distinct() + return active_ids class ContractExcludedRolesSynchronizer(Synchronizer): client_class = api.ContractsExcludedRolesAPIClient + model_class = models.ContractExcludeRoleTracker + condition_field_name = 'contractExclusionSetID' + lookup_key = 'contractExclusionSetID' + last_updated_field = None - def __init__(self, contract_exclusion_set_id=None, *args, **kwargs): - super().__init__(*args, **kwargs) - self.contract_exclusion_set_id = contract_exclusion_set_id + def _assign_field_data(self, instance, object_data): + instance.contract_exclusion_set_id = object_data[self.lookup_key] + try: + exclusion_set = models.ContractExcludedRole.objects.get(pk=instance.id) + except models.ContractExcludedRole.DoesNotExist: + instance.id = object_data[self.lookup_key] + instance.save() + + role = models.Role.objects.filter(id=object_data['excludedRoleID']).first() + instance.excluded_roles.add(role) - if contract_exclusion_set_id: - self.client.add_condition( - A(op='eq', field="contractExclusionSetID", value=self.contract_exclusion_set_id) - ) + return instance + + @property + def active_ids(self): + active_ids = models.Role.objects.exclude(contract_exclusion_set_id=None).values_list( + 'contract_exclusion_set_id', flat=True + ).distinct() + return active_ids class NoteTypeSynchronizer(PicklistSynchronizer): From f8a0349956fdde36c8c482a911f377cdf7901aae Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Mon, 21 Oct 2024 13:22:47 +0500 Subject: [PATCH 4/9] [ISSUE-3694] Add contract exclusion set sync and constraints for work types on tickets and tasks --- djautotask/admin.py | 15 ++- djautotask/api.py | 4 + djautotask/management/commands/atsync.py | 9 +- ...0118_contract_contract_exclusion_set_id.py | 18 ---- .../0118_contractexclusionset_and_more.py | 90 +++++++++++++++++ ...dworktype_contractexcludedrole_and_more.py | 53 ---------- djautotask/models.py | 55 ++++++++--- djautotask/sync.py | 97 +++++++++++++------ 8 files changed, 220 insertions(+), 121 deletions(-) delete mode 100644 djautotask/migrations/0118_contract_contract_exclusion_set_id.py create mode 100644 djautotask/migrations/0118_contractexclusionset_and_more.py delete mode 100644 djautotask/migrations/0119_contractexcludedworktype_contractexcludedrole_and_more.py diff --git a/djautotask/admin.py b/djautotask/admin.py index 0e3264b..8980a21 100644 --- a/djautotask/admin.py +++ b/djautotask/admin.py @@ -402,11 +402,18 @@ class ProjectNoteTypeAdmin(admin.ModelAdmin): @admin.register(models.CompanyAlert) class CompanyAlertsAdmin(admin.ModelAdmin): list_display = ('id', 'alert_text', 'alert_type', 'account') -@admin.register(models.ContractExcludedWorkType) + + +@admin.register(models.ContractExclusionSet) +class ContractExclusionSetAdmin(admin.ModelAdmin): + list_display = ('id', 'name', 'is_active') + + +@admin.register(models.ContractExclusionSetExcludedWorkType) class ContractExcludedWorkTypeAdmin(admin.ModelAdmin): - list_display = ('id', 'contract_exclusion_set_id') + list_display = ('id', 'contract_exclusion_set', 'excluded_work_type') -@admin.register(models.ContractExcludedRole) +@admin.register(models.ContractExclusionSetExcludedRole) class ContractExcludedRoleAdmin(admin.ModelAdmin): - list_display = ('id', 'contract_exclusion_set_id') + list_display = ('id', 'contract_exclusion_set', 'excluded_role') diff --git a/djautotask/api.py b/djautotask/api.py index d635be8..f8186f9 100644 --- a/djautotask/api.py +++ b/djautotask/api.py @@ -721,6 +721,10 @@ class ContractsAPIClient(AutotaskAPIClient): API = 'Contracts' +class ContractExclusionSetsAPIClient(AutotaskAPIClient): + API = 'ContractExclusionSets' + + class ContractsExcludedWorkTypesAPIClient(AutotaskAPIClient): API = 'ContractExclusionSetExcludedWorkTypes' diff --git a/djautotask/management/commands/atsync.py b/djautotask/management/commands/atsync.py index 07369a7..1547c5c 100644 --- a/djautotask/management/commands/atsync.py +++ b/djautotask/management/commands/atsync.py @@ -134,14 +134,19 @@ def __init__(self, *args, **kwargs): ('task_predecessor', sync.TaskPredecessorSynchronizer, _('Task Predecessor')), ('contact', sync.ContactSynchronizer, _('Contact')), + ( + 'contract_exclusion_set', + sync.ContractExclusionSetSynchronizer, + _('Contract Exclusion Set') + ), ( 'contract_excluded_worktype', - sync.ContractExcludedWorkTypesSynchronizer, + sync.ContractExcludedWorkTypeSynchronizer, _('Contract Excluded Work Type') ), ( 'contract_excluded_role', - sync.ContractExcludedRolesSynchronizer, + sync.ContractExcludedRoleSynchronizer, _('Contract Excluded Role') ), ) diff --git a/djautotask/migrations/0118_contract_contract_exclusion_set_id.py b/djautotask/migrations/0118_contract_contract_exclusion_set_id.py deleted file mode 100644 index 8b14fdf..0000000 --- a/djautotask/migrations/0118_contract_contract_exclusion_set_id.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.16 on 2024-09-27 18:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('djautotask', '0117_alter_tasknote_task_alter_ticketnote_ticket'), - ] - - operations = [ - migrations.AddField( - model_name='contract', - name='contract_exclusion_set_id', - field=models.IntegerField(blank=True, null=True), - ), - ] diff --git a/djautotask/migrations/0118_contractexclusionset_and_more.py b/djautotask/migrations/0118_contractexclusionset_and_more.py new file mode 100644 index 0000000..1b323a4 --- /dev/null +++ b/djautotask/migrations/0118_contractexclusionset_and_more.py @@ -0,0 +1,90 @@ +# Generated by Django 4.2.16 on 2024-10-20 01:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('djautotask', '0117_alter_tasknote_task_alter_ticketnote_ticket'), + ] + + operations = [ + migrations.CreateModel( + name='ContractExclusionSet', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.TextField(blank=True, null=True)), + ('is_active', models.BooleanField(default=True)), + ('name', models.CharField(max_length=255)), + ], + ), + migrations.AddField( + model_name='contract', + name='contract_exclusion_set_id', + field=models.IntegerField(blank=True, null=True), + ), + migrations.CreateModel( + name='ContractExclusionSetExcludedWorkType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('contract_exclusion_set', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='djautotask.contractexclusionset')), + ('excluded_work_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='djautotask.billingcode')), + ], + ), + migrations.CreateModel( + name='ContractExclusionSetExcludedRole', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('contract_exclusion_set', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='djautotask.contractexclusionset')), + ('excluded_role', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='djautotask.role')), + ], + ), + migrations.AddField( + model_name='contractexclusionset', + name='excluded_roles', + field=models.ManyToManyField(related_name='excluded_role_sets', through='djautotask.ContractExclusionSetExcludedRole', to='djautotask.role'), + ), + migrations.AddField( + model_name='contractexclusionset', + name='excluded_work_types', + field=models.ManyToManyField(related_name='excluded_work_type_sets', through='djautotask.ContractExclusionSetExcludedWorkType', to='djautotask.billingcode'), + ), + migrations.CreateModel( + name='ContractExcludedWorkTypeTracker', + fields=[ + ], + options={ + 'db_table': 'djautotask_contract_exclusion_setworktype', + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('djautotask.contractexclusionsetexcludedworktype',), + ), + migrations.CreateModel( + name='ContractExcludeRoleTracker', + fields=[ + ], + options={ + 'db_table': 'djautotask_contract_exclusion_setrole', + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('djautotask.contractexclusionsetexcludedrole',), + ), + migrations.CreateModel( + name='ContractExclusionSetTracker', + fields=[ + ], + options={ + 'db_table': 'djautotask_contract_exclusion_set', + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('djautotask.contractexclusionset',), + ), + ] diff --git a/djautotask/migrations/0119_contractexcludedworktype_contractexcludedrole_and_more.py b/djautotask/migrations/0119_contractexcludedworktype_contractexcludedrole_and_more.py deleted file mode 100644 index d83a13a..0000000 --- a/djautotask/migrations/0119_contractexcludedworktype_contractexcludedrole_and_more.py +++ /dev/null @@ -1,53 +0,0 @@ -# Generated by Django 4.2.16 on 2024-10-10 19:43 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('djautotask', '0118_contract_contract_exclusion_set_id'), - ] - - operations = [ - migrations.CreateModel( - name='ContractExcludedWorkType', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('contract_exclusion_set_id', models.IntegerField(blank=True, null=True)), - ('excluded_work_types', models.ManyToManyField(related_name='excluded_in_contracts', to='djautotask.billingcode')), - ], - ), - migrations.CreateModel( - name='ContractExcludedRole', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('contract_exclusion_set_id', models.IntegerField(blank=True, null=True)), - ('excluded_roles', models.ManyToManyField(related_name='excluded_in_contracts', to='djautotask.role')), - ], - ), - migrations.CreateModel( - name='ContractExcludedWorkTypeTracker', - fields=[ - ], - options={ - 'db_table': 'djautotask_contract_excluded_worktype', - 'proxy': True, - 'indexes': [], - 'constraints': [], - }, - bases=('djautotask.contractexcludedworktype',), - ), - migrations.CreateModel( - name='ContractExcludeRoleTracker', - fields=[ - ], - options={ - 'db_table': 'djautotask_contract_excluded_role', - 'proxy': True, - 'indexes': [], - 'constraints': [], - }, - bases=('djautotask.contractexcludedrole',), - ), - ] diff --git a/djautotask/models.py b/djautotask/models.py index 33bb557..6512f89 100644 --- a/djautotask/models.py +++ b/djautotask/models.py @@ -962,23 +962,38 @@ def __str__(self): return self.name -class ContractExcludedWorkType(models.Model): - contract_exclusion_set_id = models.IntegerField( - blank=True, null=True - ) +class ContractExclusionSet(models.Model): + description = models.TextField(blank=True, null=True) + is_active = models.BooleanField(default=True) + name = models.CharField(max_length=255) excluded_work_types = models.ManyToManyField( - 'BillingCode', related_name='excluded_in_contracts' - ) - - -class ContractExcludedRole(models.Model): - contract_exclusion_set_id = models.IntegerField( - blank=True, null=True + 'BillingCode', through='ContractExclusionSetExcludedWorkType', + related_name='excluded_work_type_sets' ) excluded_roles = models.ManyToManyField( - 'Role', related_name='excluded_in_contracts' + 'Role', through='ContractExclusionSetExcludedRole', + related_name='excluded_role_sets' ) + def __str__(self): + return self.name + + +class ContractExclusionSetExcludedWorkType(models.Model): + contract_exclusion_set = models.ForeignKey('ContractExclusionSet', on_delete=models.CASCADE) + excluded_work_type = models.ForeignKey('BillingCode', on_delete=models.CASCADE) + + def __str__(self): + return f"{self.contract_exclusion_set.name} - {self.excluded_work_type.name}" + + +class ContractExclusionSetExcludedRole(models.Model): + contract_exclusion_set = models.ForeignKey('ContractExclusionSet', on_delete=models.CASCADE) + excluded_role = models.ForeignKey('Role', on_delete=models.CASCADE) + + def __str__(self): + return f"{self.contract_exclusion_set.name} - {self.excluded_role.name}" + class ServiceCall(TimeStampedModel): description = models.TextField(blank=True, null=True, max_length=2000) @@ -1483,20 +1498,28 @@ class Meta: db_table = 'djautotask_contract' -class ContractExcludedWorkTypeTracker(ContractExcludedWorkType): +class ContractExclusionSetTracker(ContractExclusionSet): + tracker = FieldTracker() + + class Meta: + proxy = True + db_table = 'djautotask_contract_exclusion_set' + + +class ContractExcludedWorkTypeTracker(ContractExclusionSetExcludedWorkType): tracker = FieldTracker() class Meta: proxy = True - db_table = 'djautotask_contract_excluded_worktype' + db_table = 'djautotask_contract_exclusion_setworktype' -class ContractExcludeRoleTracker(ContractExcludedRole): +class ContractExcludeRoleTracker(ContractExclusionSetExcludedRole): tracker = FieldTracker() class Meta: proxy = True - db_table = 'djautotask_contract_excluded_role' + db_table = 'djautotask_contract_exclusion_setrole' class ServiceCallTracker(ServiceCall): diff --git a/djautotask/sync.py b/djautotask/sync.py index 2fe9cb1..5fe92c3 100644 --- a/djautotask/sync.py +++ b/djautotask/sync.py @@ -2004,59 +2004,100 @@ def active_ids(self): return active_ids -class ContractExcludedWorkTypesSynchronizer(BatchQueryMixin, Synchronizer): +class CompanyAlertSynchronizer(BatchQueryMixin, Synchronizer): + client_class = api.CompanyAlertAPIClient + model_class = models.CompanyAlertTracker + condition_field_name = 'companyID' + last_updated_field = None + + related_meta = { + 'companyID': (models.Account, 'account'), + } + + def _assign_field_data(self, instance, object_data): + instance.id = object_data['id'] + instance.alert_text = object_data.get('alertText') + instance.alert_type = object_data.get('alertTypeID') + + self.set_relations(instance, object_data) + + return instance + + @property + def active_ids(self): + active_ids = models.Account.objects.all().\ + values_list('id', flat=True).order_by(self.lookup_key) + + return active_ids + + +class ContractExclusionSetSynchronizer(Synchronizer): + client_class = api.ContractExclusionSetsAPIClient + model_class = models.ContractExclusionSetTracker + last_updated_field = None + + def _assign_field_data(self, instance, object_data): + instance.id = object_data['id'] + instance.name = object_data['name'] + instance.is_active = object_data['isActive'] + instance.description = object_data['description'] + + return instance + + +class ContractExcludedWorkTypeSynchronizer(BatchQueryMixin, Synchronizer): client_class = api.ContractsExcludedWorkTypesAPIClient model_class = models.ContractExcludedWorkTypeTracker condition_field_name = 'contractExclusionSetID' - lookup_key = 'contractExclusionSetID' last_updated_field = None + related_meta = { + 'contractExclusionSetID': + (models.ContractExclusionSet, 'contract_exclusion_set'), + 'excludedWorkTypeID': (models.BillingCode, 'excluded_work_type') + } + def _assign_field_data(self, instance, object_data): - instance.contract_exclusion_set_id = object_data[self.lookup_key] - try: - exclusion_set = models.ContractExcludedWorkType.objects.get(pk=instance.id) - except models.ContractExcludedWorkType.DoesNotExist: - instance.id = object_data[self.lookup_key] - instance.save() - - work_type = models.BillingCode.objects.filter(id=object_data['excludedWorkTypeID'], use_type=1).first() - instance.excluded_work_types.add(work_type) + instance.id = object_data['id'] + self.set_relations(instance, object_data) return instance @property def active_ids(self): - active_ids = models.Contract.objects.exclude(contract_exclusion_set_id=None).values_list( - 'contract_exclusion_set_id', flat=True - ).distinct() + active_ids = models.ContractExclusionSet.objects.exclude( + is_active=False + ).values_list( + 'id', flat=True + ) return active_ids -class ContractExcludedRolesSynchronizer(Synchronizer): +class ContractExcludedRoleSynchronizer(BatchQueryMixin, Synchronizer): client_class = api.ContractsExcludedRolesAPIClient model_class = models.ContractExcludeRoleTracker condition_field_name = 'contractExclusionSetID' - lookup_key = 'contractExclusionSetID' last_updated_field = None + + related_meta = { + 'contractExclusionSetID': + (models.ContractExclusionSet, 'contract_exclusion_set'), + 'excludedRoleID': (models.Role, 'excluded_role') + } def _assign_field_data(self, instance, object_data): - instance.contract_exclusion_set_id = object_data[self.lookup_key] - try: - exclusion_set = models.ContractExcludedRole.objects.get(pk=instance.id) - except models.ContractExcludedRole.DoesNotExist: - instance.id = object_data[self.lookup_key] - instance.save() - - role = models.Role.objects.filter(id=object_data['excludedRoleID']).first() - instance.excluded_roles.add(role) + instance.id = object_data['id'] + self.set_relations(instance, object_data) return instance @property def active_ids(self): - active_ids = models.Role.objects.exclude(contract_exclusion_set_id=None).values_list( - 'contract_exclusion_set_id', flat=True - ).distinct() + active_ids = models.ContractExclusionSet.objects.exclude( + is_active=False + ).values_list( + 'id', flat=True + ) return active_ids From 4ebb17321200ae084e6e35be8aec773354f6a695 Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Fri, 25 Oct 2024 16:23:17 +0500 Subject: [PATCH 5/9] Updated Unit Tests --- djautotask/admin.py | 3 +- .../0118_contractexclusionset_and_more.py | 8 +-- djautotask/models.py | 25 ++++--- djautotask/sync.py | 5 +- djautotask/tests/fixture_utils.py | 25 +++++++ djautotask/tests/fixtures.py | 38 +++++++++- djautotask/tests/mocks.py | 15 ++++ djautotask/tests/test_commands.py | 64 ++++++++++++++++- djautotask/tests/test_sync.py | 70 +++++++++++++++++++ 9 files changed, 236 insertions(+), 17 deletions(-) diff --git a/djautotask/admin.py b/djautotask/admin.py index 8980a21..6eb2ef1 100644 --- a/djautotask/admin.py +++ b/djautotask/admin.py @@ -305,7 +305,8 @@ class ResourceServiceDeskRoleAdmin(admin.ModelAdmin): @admin.register(models.Contract) class ContractAdmin(admin.ModelAdmin): - list_display = ('id', 'name', 'number', 'account', 'status_name', 'contract_exclusion_set_id') + list_display = ('id', 'name', 'number', 'account', 'status_name', + 'contract_exclusion_set_id') search_fields = ('id', 'name', 'number') list_filter = ('status',) diff --git a/djautotask/migrations/0118_contractexclusionset_and_more.py b/djautotask/migrations/0118_contractexclusionset_and_more.py index 1b323a4..c7b2bd0 100644 --- a/djautotask/migrations/0118_contractexclusionset_and_more.py +++ b/djautotask/migrations/0118_contractexclusionset_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.16 on 2024-10-20 01:35 +# Generated by Django 4.2.16 on 2024-10-25 15:25 from django.db import migrations, models import django.db.models.deletion @@ -56,7 +56,7 @@ class Migration(migrations.Migration): fields=[ ], options={ - 'db_table': 'djautotask_contract_exclusion_setworktype', + 'db_table': 'djautotask_contractexclusionsetworktype', 'proxy': True, 'indexes': [], 'constraints': [], @@ -68,7 +68,7 @@ class Migration(migrations.Migration): fields=[ ], options={ - 'db_table': 'djautotask_contract_exclusion_setrole', + 'db_table': 'djautotask_contractexclusionsetrole', 'proxy': True, 'indexes': [], 'constraints': [], @@ -80,7 +80,7 @@ class Migration(migrations.Migration): fields=[ ], options={ - 'db_table': 'djautotask_contract_exclusion_set', + 'db_table': 'djautotask_contractexclusionset', 'proxy': True, 'indexes': [], 'constraints': [], diff --git a/djautotask/models.py b/djautotask/models.py index 6512f89..d84213a 100644 --- a/djautotask/models.py +++ b/djautotask/models.py @@ -980,19 +980,28 @@ def __str__(self): class ContractExclusionSetExcludedWorkType(models.Model): - contract_exclusion_set = models.ForeignKey('ContractExclusionSet', on_delete=models.CASCADE) - excluded_work_type = models.ForeignKey('BillingCode', on_delete=models.CASCADE) + contract_exclusion_set = models.ForeignKey('ContractExclusionSet', + on_delete=models.CASCADE) + excluded_work_type = models.ForeignKey('BillingCode', + on_delete=models.CASCADE) def __str__(self): - return f"{self.contract_exclusion_set.name} - {self.excluded_work_type.name}" + return ( + f"{self.contract_exclusion_set.name} - " + f"{self.excluded_work_type.name}" + ) class ContractExclusionSetExcludedRole(models.Model): - contract_exclusion_set = models.ForeignKey('ContractExclusionSet', on_delete=models.CASCADE) + contract_exclusion_set = models.ForeignKey('ContractExclusionSet', + on_delete=models.CASCADE) excluded_role = models.ForeignKey('Role', on_delete=models.CASCADE) def __str__(self): - return f"{self.contract_exclusion_set.name} - {self.excluded_role.name}" + return ( + f"{self.contract_exclusion_set.name} - " + f"{self.excluded_work_type.name}" + ) class ServiceCall(TimeStampedModel): @@ -1503,7 +1512,7 @@ class ContractExclusionSetTracker(ContractExclusionSet): class Meta: proxy = True - db_table = 'djautotask_contract_exclusion_set' + db_table = 'djautotask_contractexclusionset' class ContractExcludedWorkTypeTracker(ContractExclusionSetExcludedWorkType): @@ -1511,7 +1520,7 @@ class ContractExcludedWorkTypeTracker(ContractExclusionSetExcludedWorkType): class Meta: proxy = True - db_table = 'djautotask_contract_exclusion_setworktype' + db_table = 'djautotask_contractexclusionsetworktype' class ContractExcludeRoleTracker(ContractExclusionSetExcludedRole): @@ -1519,7 +1528,7 @@ class ContractExcludeRoleTracker(ContractExclusionSetExcludedRole): class Meta: proxy = True - db_table = 'djautotask_contract_exclusion_setrole' + db_table = 'djautotask_contractexclusionsetrole' class ServiceCallTracker(ServiceCall): diff --git a/djautotask/sync.py b/djautotask/sync.py index 5fe92c3..d1e38d6 100644 --- a/djautotask/sync.py +++ b/djautotask/sync.py @@ -1812,7 +1812,8 @@ def _assign_field_data(self, instance, object_data): instance.name = object_data.get('contractName') instance.number = object_data.get('contractNumber') instance.status = str(object_data.get('status')) - instance.contract_exclusion_set_id = object_data.get('contractExclusionSetID') + instance.contract_exclusion_set_id = \ + object_data.get('contractExclusionSetID') self.set_relations(instance, object_data) @@ -2078,7 +2079,7 @@ class ContractExcludedRoleSynchronizer(BatchQueryMixin, Synchronizer): model_class = models.ContractExcludeRoleTracker condition_field_name = 'contractExclusionSetID' last_updated_field = None - + related_meta = { 'contractExclusionSetID': (models.ContractExclusionSet, 'contract_exclusion_set'), diff --git a/djautotask/tests/fixture_utils.py b/djautotask/tests/fixture_utils.py index 5a9e324..d9f2b30 100644 --- a/djautotask/tests/fixture_utils.py +++ b/djautotask/tests/fixture_utils.py @@ -339,6 +339,31 @@ def init_contracts(): return synchronizer.sync() +def init_contracts_exclusion_sets(): + models.ContractExclusionSet.objects.all().delete() + mocks.service_api_get_contracts_exclusions_sets_call( + fixtures.API_CONTRACT_EXCLUSION_SET) + synchronizer = sync.ContractExclusionSetSynchronizer() + return synchronizer.sync() + + +def init_contracts_exclusion_roles(): + models.ContractExclusionSetExcludedRole.objects.all() \ + .delete() + mocks.service_api_get_contracts_excluded_roles_call( + fixtures.API_CONTRACT_EXCLUSION_ROLE) + synchronizer = sync.ContractExcludedRoleSynchronizer() + return synchronizer.sync() + + +def init_contracts_exlusion_work_types(): + models.ContractExclusionSetExcludedWorkType.objects.all().delete() + mocks.service_api_get_contracts_excluded_work_types_call( + fixtures.API_CONTRACT_EXCLUSION_WORK_TYPE) + synchronizer = sync.ContractExcludedWorkTypeSynchronizer() + return synchronizer.sync() + + def init_service_calls(): models.ServiceCall.objects.all().delete() mocks.service_api_get_service_calls_call(fixtures.API_SERVICE_CALL) diff --git a/djautotask/tests/fixtures.py b/djautotask/tests/fixtures.py index 29c4820..aee27f6 100644 --- a/djautotask/tests/fixtures.py +++ b/djautotask/tests/fixtures.py @@ -1272,6 +1272,7 @@ 'serviceLevelAgreementID': 1, 'purchaseOrderNumber': "", 'internalCurrencySetupFee': 995.0000, + 'contractExclusionSetID': 1, } ] API_CONTRACT = { @@ -1445,4 +1446,39 @@ API_COMPANY_ALERTS = { "items": API_COMPANY_ALERT_ITEMS, "pageDetails": API_PAGE_DETAILS -} \ No newline at end of file +} + +API_CONTRACT_EXCLUSION_SET_ITEM = { + "id": 1, + "description": "Sample Set", + "isActive": True, + "name": "Set1", +} +API_CONTRACT_EXCLUSION_SET_ITEMS = [API_CONTRACT_EXCLUSION_SET_ITEM] +API_CONTRACT_EXCLUSION_SET = { + "items": API_CONTRACT_EXCLUSION_SET_ITEMS, + "pageDetails": API_PAGE_DETAILS +} + +API_CONTRACT_EXCLUSION_ROLE_ITEM = { + "id": 1, + "contractExclusionSetID": 1, + "excludedRoleID": 29683399 +} +API_CONTRACT_EXCLUSION_ROLE_ITEMS = [API_CONTRACT_EXCLUSION_ROLE_ITEM] +API_CONTRACT_EXCLUSION_ROLE = { + "items": API_CONTRACT_EXCLUSION_ROLE_ITEMS, + "pageDetails": API_PAGE_DETAILS +} + + +API_CONTRACT_EXCLUSION_WORK_TYPE_ITEM = { + "id": 1, + "contractExclusionSetID": 1, + "excludedWorkTypeID": 2968341 +} +API_CONTRACT_EXCLUSION_WORK_TYPE_ITEMS = [API_CONTRACT_EXCLUSION_WORK_TYPE_ITEM] +API_CONTRACT_EXCLUSION_WORK_TYPE = { + "items": API_CONTRACT_EXCLUSION_WORK_TYPE_ITEMS, + "pageDetails": API_PAGE_DETAILS +} diff --git a/djautotask/tests/mocks.py b/djautotask/tests/mocks.py index 09bac79..d94da20 100644 --- a/djautotask/tests/mocks.py +++ b/djautotask/tests/mocks.py @@ -59,6 +59,21 @@ def service_api_get_contracts_call(return_value): return create_mock_call(method_name, return_value) +def service_api_get_contracts_exclusions_sets_call(return_value): + method_name = 'djautotask.api.ContractExclusionSetsAPIClient.get' + return create_mock_call(method_name, return_value) + + +def service_api_get_contracts_excluded_roles_call(return_value): + method_name = 'djautotask.api.ContractsExcludedRolesAPIClient.get' + return create_mock_call(method_name, return_value) + + +def service_api_get_contracts_excluded_work_types_call(return_value): + method_name = 'djautotask.api.ContractsExcludedWorkTypesAPIClient.get' + return create_mock_call(method_name, return_value) + + def service_api_get_billing_codes_call(return_value): method_name = 'djautotask.api.BillingCodesAPIClient.get' return create_mock_call(method_name, return_value) diff --git a/djautotask/tests/test_commands.py b/djautotask/tests/test_commands.py index fc16d94..689f7d8 100644 --- a/djautotask/tests/test_commands.py +++ b/djautotask/tests/test_commands.py @@ -611,6 +611,42 @@ def setUp(self): fixture_utils.init_contracts() +class TestSyncContractExclusionSetCommand(AbstractBaseSyncTest, TestCase): + args = ( + mocks.service_api_get_contracts_exclusions_sets_call, + fixtures.API_CONTRACT_EXCLUSION_SET, + 'contract_exclusion_set', + ) + + def setUp(self): + super().setUp() + + +class TestSyncContractExclusionRoleCommand(AbstractBaseSyncTest, TestCase): + args = ( + mocks.service_api_get_contracts_excluded_roles_call, + fixtures.API_CONTRACT_EXCLUSION_ROLE, + 'contract_exclusion_role', + ) + + def setUp(self): + super().setUp() + fixture_utils.init_contracts_exclusion_sets() + + +class TestSyncContractExclusionWorkTypeCommand(AbstractBaseSyncTest, + TestCase): + args = ( + mocks.service_api_get_contracts_excluded_work_types_call, + fixtures.API_CONTRACT_EXCLUSION_WORK_TYPE, + 'contract_exclusion_work_type', + ) + + def setUp(self): + super().setUp() + fixture_utils.init_contracts_exclusion_sets() + + class TestSyncServiceCallCommand(AbstractBaseSyncTest, TestCase): args = ( mocks.service_api_get_service_calls_call, @@ -786,6 +822,9 @@ def setUp(self): TestSyncTaskPredecessor, TestSyncContactCommand, TestSyncCompanyAlertsCommand, + TestSyncContractExclusionSetCommand, + TestSyncContractExclusionRoleCommand, + TestSyncContractExclusionWorkTypeCommand, ] self.test_args = [] @@ -868,6 +907,11 @@ def test_full_sync(self): 'task_predecessor': models.TaskPredecessor, 'contact': models.Contact, 'company_alert': models.CompanyAlert, + 'contract_exclusion_set': models.ContractExclusionSet, + 'contract_exclusion_role': + models.ContractExclusionSetExcludedRole, + 'contract_exclusion_work_type': + models.ContractExclusionSetExcludedWorkType, } run_sync_command() pre_full_sync_counts = {} @@ -890,7 +934,10 @@ def test_full_sync(self): 'service_call_task_resource', 'task_predecessor', 'task', - 'time_entry' + 'time_entry', + 'contract_exclusion_set', + 'contract_exclusion_role', + 'contract_exclusion_work_type', ): # Assert that there were objects to get deleted, then change # to zero to verify the output formats correctly. @@ -971,6 +1018,15 @@ def _call_service_api(self): fixtures.API_TASK_PREDECESSOR) mocks.service_api_get_company_alerts_call( fixtures.API_COMPANY_ALERTS) + mocks.service_api_get_contracts_exclusions_sets_call( + fixtures.API_CONTRACT_EXCLUSION_SET + ) + mocks.service_api_get_contracts_excluded_roles_call( + fixtures.API_CONTRACT_EXCLUSION_ROLE + ) + mocks.service_api_get_contracts_excluded_work_types_call( + fixtures.API_CONTRACT_EXCLUSION_ROLE + ) def _call_empty_service_api(self): mocks.service_api_get_ticket_udf_call(fixtures.API_EMPTY_FIELDS) @@ -1026,3 +1082,9 @@ def _call_empty_service_api(self): fixtures.API_EMPTY_FIELDS) mocks.service_api_get_task_picklist_call(fixtures.API_EMPTY_FIELDS) mocks.service_api_get_company_alerts_call(fixtures.API_COMPANY_ALERTS) + mocks.service_api_get_contracts_exclusions_sets_call( + fixtures.API_CONTRACT_EXCLUSION_SET) + mocks.service_api_get_contracts_excluded_roles_call( + fixtures.API_CONTRACT_EXCLUSION_ROLE) + mocks.service_api_get_contracts_excluded_work_types_call( + fixtures.API_CONTRACT_EXCLUSION_WORK_TYPE) diff --git a/djautotask/tests/test_sync.py b/djautotask/tests/test_sync.py index 72427e9..90dfb8c 100644 --- a/djautotask/tests/test_sync.py +++ b/djautotask/tests/test_sync.py @@ -1159,6 +1159,76 @@ def _assert_fields(self, instance, object_data): self.assertEqual(instance.number, object_data['contractNumber']) self.assertEqual(instance.status, str(object_data['status'])) self.assertEqual(instance.account.id, object_data['companyID']) + self.assertEqual(instance.contract_exclusion_set_id, + object_data['contractExclusionSetID']) + + +class TestContractExclusionSetSynchronizer(SynchronizerTestMixin, TestCase): + synchronizer_class = sync.ContractExclusionSetSynchronizer + model_class = models.ContractExclusionSetTracker + fixture = fixtures.API_CONTRACT_EXCLUSION_SET + update_field = 'name' + + def setUp(self): + super().setUp() + self._sync(self.fixture) + + def _call_api(self, return_data): + return mocks.service_api_get_contracts_exclusions_sets_call( + return_data) + + def _assert_fields(self, instance, object_data): + self.assertEqual(instance.id, object_data['id']) + self.assertEqual(instance.description, object_data['description']) + self.assertEqual(instance.isActive, object_data['isActive']) + self.assertEqual(instance.name, object_data['name']) + + +class TestContractExclusionRoleSynchronizer(SynchronizerTestMixin, TestCase): + synchronizer_class = sync.ContractExcludedRoleSynchronizer + model_class = models.ContractExcludeRoleTracker + fixture = fixtures.API_CONTRACT_EXCLUSION_ROLE + update_field = 'excluded_role_id' + + def setUp(self): + super().setUp() + fixture_utils.init_contracts_exclusion_sets() + self._sync(self.fixture) + + def _call_api(self, return_data): + return mocks.service_api_get_contracts_excluded_roles_call( + return_data) + + def _assert_fields(self, instance, object_data): + self.assertEqual(instance.id, object_data['id']) + self.assertEqual(instance.contract_exclusion_set.id, + object_data['contractExclusionSetID']) + self.assertEqual(instance.excluded_role.id, + object_data['excludedRoleID']) + + +class TestContractExclusionWorkTypeSynchronizer(SynchronizerTestMixin, + TestCase): + synchronizer_class = sync.ContractExcludedWorkTypeSynchronizer + model_class = models.ContractExcludedWorkTypeTracker + fixture = fixtures.API_CONTRACT_EXCLUSION_WORK_TYPE + update_field = 'excluded_work_type_id' + + def setUp(self): + super().setUp() + fixture_utils.init_contracts_exclusion_sets() + self._sync(self.fixture) + + def _call_api(self, return_data): + return mocks.service_api_get_contracts_excluded_work_types_call( + return_data) + + def _assert_fields(self, instance, object_data): + self.assertEqual(instance.id, object_data['id']) + self.assertEqual(instance.contract_exclusion_set.id, + object_data['contractExclusionSetID']) + self.assertEqual(instance.excluded_work_type.id, object_data[ + 'excludedWorkTypeID']) class TestCompanyAlertsSynchronizer(SynchronizerTestMixin, TestCase): From 22b87214dab2e67244a440f4da8cd1a37191e7d7 Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Wed, 30 Oct 2024 23:53:14 +0500 Subject: [PATCH 6/9] Updated test cases --- djautotask/api.py | 6 +-- djautotask/management/commands/atsync.py | 2 +- .../0118_contractexclusionset_and_more.py | 14 +++--- djautotask/models.py | 12 ++--- djautotask/sync.py | 8 +-- djautotask/tests/fixture_utils.py | 12 ++--- djautotask/tests/fixtures.py | 4 +- djautotask/tests/mocks.py | 12 ++--- djautotask/tests/test_commands.py | 50 ++++++++++--------- djautotask/tests/test_sync.py | 20 ++++---- 10 files changed, 70 insertions(+), 70 deletions(-) diff --git a/djautotask/api.py b/djautotask/api.py index f8186f9..77d2228 100644 --- a/djautotask/api.py +++ b/djautotask/api.py @@ -721,15 +721,15 @@ class ContractsAPIClient(AutotaskAPIClient): API = 'Contracts' -class ContractExclusionSetsAPIClient(AutotaskAPIClient): +class ContractExclusionSetAPIClient(AutotaskAPIClient): API = 'ContractExclusionSets' -class ContractsExcludedWorkTypesAPIClient(AutotaskAPIClient): +class ContractsExcludedWorkTypeAPIClient(AutotaskAPIClient): API = 'ContractExclusionSetExcludedWorkTypes' -class ContractsExcludedRolesAPIClient(AutotaskAPIClient): +class ContractsExcludedRoleAPIClient(AutotaskAPIClient): API = 'ContractExclusionSetExcludedRoles' diff --git a/djautotask/management/commands/atsync.py b/djautotask/management/commands/atsync.py index 1547c5c..d0d4035 100644 --- a/djautotask/management/commands/atsync.py +++ b/djautotask/management/commands/atsync.py @@ -140,7 +140,7 @@ def __init__(self, *args, **kwargs): _('Contract Exclusion Set') ), ( - 'contract_excluded_worktype', + 'contract_excluded_work_type', sync.ContractExcludedWorkTypeSynchronizer, _('Contract Excluded Work Type') ), diff --git a/djautotask/migrations/0118_contractexclusionset_and_more.py b/djautotask/migrations/0118_contractexclusionset_and_more.py index c7b2bd0..19796be 100644 --- a/djautotask/migrations/0118_contractexclusionset_and_more.py +++ b/djautotask/migrations/0118_contractexclusionset_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.16 on 2024-10-25 15:25 +# Generated by Django 4.2.16 on 2024-10-30 23:14 from django.db import migrations, models import django.db.models.deletion @@ -52,28 +52,28 @@ class Migration(migrations.Migration): field=models.ManyToManyField(related_name='excluded_work_type_sets', through='djautotask.ContractExclusionSetExcludedWorkType', to='djautotask.billingcode'), ), migrations.CreateModel( - name='ContractExcludedWorkTypeTracker', + name='ContractExcludedRoleTracker', fields=[ ], options={ - 'db_table': 'djautotask_contractexclusionsetworktype', + 'db_table': 'djautotask_contractexclusionsetrole', 'proxy': True, 'indexes': [], 'constraints': [], }, - bases=('djautotask.contractexclusionsetexcludedworktype',), + bases=('djautotask.contractexclusionsetexcludedrole',), ), migrations.CreateModel( - name='ContractExcludeRoleTracker', + name='ContractExcludedWorkTypeTracker', fields=[ ], options={ - 'db_table': 'djautotask_contractexclusionsetrole', + 'db_table': 'djautotask_contractexclusionsetworktype', 'proxy': True, 'indexes': [], 'constraints': [], }, - bases=('djautotask.contractexclusionsetexcludedrole',), + bases=('djautotask.contractexclusionsetexcludedworktype',), ), migrations.CreateModel( name='ContractExclusionSetTracker', diff --git a/djautotask/models.py b/djautotask/models.py index d84213a..92397bf 100644 --- a/djautotask/models.py +++ b/djautotask/models.py @@ -986,10 +986,7 @@ class ContractExclusionSetExcludedWorkType(models.Model): on_delete=models.CASCADE) def __str__(self): - return ( - f"{self.contract_exclusion_set.name} - " - f"{self.excluded_work_type.name}" - ) + return str(self.id) or '' class ContractExclusionSetExcludedRole(models.Model): @@ -998,10 +995,7 @@ class ContractExclusionSetExcludedRole(models.Model): excluded_role = models.ForeignKey('Role', on_delete=models.CASCADE) def __str__(self): - return ( - f"{self.contract_exclusion_set.name} - " - f"{self.excluded_work_type.name}" - ) + return str(self.id) or '' class ServiceCall(TimeStampedModel): @@ -1523,7 +1517,7 @@ class Meta: db_table = 'djautotask_contractexclusionsetworktype' -class ContractExcludeRoleTracker(ContractExclusionSetExcludedRole): +class ContractExcludedRoleTracker(ContractExclusionSetExcludedRole): tracker = FieldTracker() class Meta: diff --git a/djautotask/sync.py b/djautotask/sync.py index d1e38d6..df120ef 100644 --- a/djautotask/sync.py +++ b/djautotask/sync.py @@ -2033,7 +2033,7 @@ def active_ids(self): class ContractExclusionSetSynchronizer(Synchronizer): - client_class = api.ContractExclusionSetsAPIClient + client_class = api.ContractExclusionSetAPIClient model_class = models.ContractExclusionSetTracker last_updated_field = None @@ -2047,7 +2047,7 @@ def _assign_field_data(self, instance, object_data): class ContractExcludedWorkTypeSynchronizer(BatchQueryMixin, Synchronizer): - client_class = api.ContractsExcludedWorkTypesAPIClient + client_class = api.ContractsExcludedWorkTypeAPIClient model_class = models.ContractExcludedWorkTypeTracker condition_field_name = 'contractExclusionSetID' last_updated_field = None @@ -2075,8 +2075,8 @@ def active_ids(self): class ContractExcludedRoleSynchronizer(BatchQueryMixin, Synchronizer): - client_class = api.ContractsExcludedRolesAPIClient - model_class = models.ContractExcludeRoleTracker + client_class = api.ContractsExcludedRoleAPIClient + model_class = models.ContractExcludedRoleTracker condition_field_name = 'contractExclusionSetID' last_updated_field = None diff --git a/djautotask/tests/fixture_utils.py b/djautotask/tests/fixture_utils.py index d9f2b30..eaa3d97 100644 --- a/djautotask/tests/fixture_utils.py +++ b/djautotask/tests/fixture_utils.py @@ -339,26 +339,26 @@ def init_contracts(): return synchronizer.sync() -def init_contracts_exclusion_sets(): +def init_contract_exclusion_sets(): models.ContractExclusionSet.objects.all().delete() - mocks.service_api_get_contracts_exclusions_sets_call( + mocks.service_api_get_contract_exclusion_sets_call( fixtures.API_CONTRACT_EXCLUSION_SET) synchronizer = sync.ContractExclusionSetSynchronizer() return synchronizer.sync() -def init_contracts_exclusion_roles(): +def init_contract_exclusion_roles(): models.ContractExclusionSetExcludedRole.objects.all() \ .delete() - mocks.service_api_get_contracts_excluded_roles_call( + mocks.service_api_get_contract_excluded_roles_call( fixtures.API_CONTRACT_EXCLUSION_ROLE) synchronizer = sync.ContractExcludedRoleSynchronizer() return synchronizer.sync() -def init_contracts_exlusion_work_types(): +def init_contract_exclusion_work_types(): models.ContractExclusionSetExcludedWorkType.objects.all().delete() - mocks.service_api_get_contracts_excluded_work_types_call( + mocks.service_api_get_contract_excluded_work_types_call( fixtures.API_CONTRACT_EXCLUSION_WORK_TYPE) synchronizer = sync.ContractExcludedWorkTypeSynchronizer() return synchronizer.sync() diff --git a/djautotask/tests/fixtures.py b/djautotask/tests/fixtures.py index aee27f6..da2df96 100644 --- a/djautotask/tests/fixtures.py +++ b/djautotask/tests/fixtures.py @@ -1463,7 +1463,7 @@ API_CONTRACT_EXCLUSION_ROLE_ITEM = { "id": 1, "contractExclusionSetID": 1, - "excludedRoleID": 29683399 + "excludedRoleID": 8 } API_CONTRACT_EXCLUSION_ROLE_ITEMS = [API_CONTRACT_EXCLUSION_ROLE_ITEM] API_CONTRACT_EXCLUSION_ROLE = { @@ -1475,7 +1475,7 @@ API_CONTRACT_EXCLUSION_WORK_TYPE_ITEM = { "id": 1, "contractExclusionSetID": 1, - "excludedWorkTypeID": 2968341 + "excludedWorkTypeID": 2 } API_CONTRACT_EXCLUSION_WORK_TYPE_ITEMS = [API_CONTRACT_EXCLUSION_WORK_TYPE_ITEM] API_CONTRACT_EXCLUSION_WORK_TYPE = { diff --git a/djautotask/tests/mocks.py b/djautotask/tests/mocks.py index d94da20..1cac0ab 100644 --- a/djautotask/tests/mocks.py +++ b/djautotask/tests/mocks.py @@ -59,18 +59,18 @@ def service_api_get_contracts_call(return_value): return create_mock_call(method_name, return_value) -def service_api_get_contracts_exclusions_sets_call(return_value): - method_name = 'djautotask.api.ContractExclusionSetsAPIClient.get' +def service_api_get_contract_exclusion_sets_call(return_value): + method_name = 'djautotask.api.ContractExclusionSetAPIClient.get' return create_mock_call(method_name, return_value) -def service_api_get_contracts_excluded_roles_call(return_value): - method_name = 'djautotask.api.ContractsExcludedRolesAPIClient.get' +def service_api_get_contract_excluded_roles_call(return_value): + method_name = 'djautotask.api.ContractsExcludedRoleAPIClient.get' return create_mock_call(method_name, return_value) -def service_api_get_contracts_excluded_work_types_call(return_value): - method_name = 'djautotask.api.ContractsExcludedWorkTypesAPIClient.get' +def service_api_get_contract_excluded_work_types_call(return_value): + method_name = 'djautotask.api.ContractsExcludedWorkTypeAPIClient.get' return create_mock_call(method_name, return_value) diff --git a/djautotask/tests/test_commands.py b/djautotask/tests/test_commands.py index 689f7d8..22fd9cc 100644 --- a/djautotask/tests/test_commands.py +++ b/djautotask/tests/test_commands.py @@ -613,38 +613,43 @@ def setUp(self): class TestSyncContractExclusionSetCommand(AbstractBaseSyncTest, TestCase): args = ( - mocks.service_api_get_contracts_exclusions_sets_call, + mocks.service_api_get_contract_exclusion_sets_call, fixtures.API_CONTRACT_EXCLUSION_SET, 'contract_exclusion_set', ) def setUp(self): super().setUp() + fixture_utils.init_contract_exclusion_sets() class TestSyncContractExclusionRoleCommand(AbstractBaseSyncTest, TestCase): args = ( - mocks.service_api_get_contracts_excluded_roles_call, + mocks.service_api_get_contract_excluded_roles_call, fixtures.API_CONTRACT_EXCLUSION_ROLE, - 'contract_exclusion_role', + 'contract_excluded_role', ) def setUp(self): super().setUp() - fixture_utils.init_contracts_exclusion_sets() + fixture_utils.init_roles() + fixture_utils.init_contract_exclusion_sets() + fixture_utils.init_contract_exclusion_roles() class TestSyncContractExclusionWorkTypeCommand(AbstractBaseSyncTest, TestCase): args = ( - mocks.service_api_get_contracts_excluded_work_types_call, + mocks.service_api_get_contract_excluded_work_types_call, fixtures.API_CONTRACT_EXCLUSION_WORK_TYPE, - 'contract_exclusion_work_type', + 'contract_excluded_work_type', ) def setUp(self): super().setUp() - fixture_utils.init_contracts_exclusion_sets() + fixture_utils.init_billing_codes() + fixture_utils.init_contract_exclusion_sets() + fixture_utils.init_contract_exclusion_work_types() class TestSyncServiceCallCommand(AbstractBaseSyncTest, TestCase): @@ -908,9 +913,9 @@ def test_full_sync(self): 'contact': models.Contact, 'company_alert': models.CompanyAlert, 'contract_exclusion_set': models.ContractExclusionSet, - 'contract_exclusion_role': + 'contract_excluded_role': models.ContractExclusionSetExcludedRole, - 'contract_exclusion_work_type': + 'contract_excluded_work_type': models.ContractExclusionSetExcludedWorkType, } run_sync_command() @@ -935,9 +940,8 @@ def test_full_sync(self): 'task_predecessor', 'task', 'time_entry', - 'contract_exclusion_set', - 'contract_exclusion_role', - 'contract_exclusion_work_type', + 'contract_excluded_role', + 'contract_excluded_work_type', ): # Assert that there were objects to get deleted, then change # to zero to verify the output formats correctly. @@ -1018,14 +1022,14 @@ def _call_service_api(self): fixtures.API_TASK_PREDECESSOR) mocks.service_api_get_company_alerts_call( fixtures.API_COMPANY_ALERTS) - mocks.service_api_get_contracts_exclusions_sets_call( + mocks.service_api_get_contract_exclusion_sets_call( fixtures.API_CONTRACT_EXCLUSION_SET ) - mocks.service_api_get_contracts_excluded_roles_call( + mocks.service_api_get_contract_excluded_roles_call( fixtures.API_CONTRACT_EXCLUSION_ROLE ) - mocks.service_api_get_contracts_excluded_work_types_call( - fixtures.API_CONTRACT_EXCLUSION_ROLE + mocks.service_api_get_contract_excluded_work_types_call( + fixtures.API_CONTRACT_EXCLUSION_WORK_TYPE ) def _call_empty_service_api(self): @@ -1081,10 +1085,10 @@ def _call_empty_service_api(self): mocks.service_api_get_project_note_types_call( fixtures.API_EMPTY_FIELDS) mocks.service_api_get_task_picklist_call(fixtures.API_EMPTY_FIELDS) - mocks.service_api_get_company_alerts_call(fixtures.API_COMPANY_ALERTS) - mocks.service_api_get_contracts_exclusions_sets_call( - fixtures.API_CONTRACT_EXCLUSION_SET) - mocks.service_api_get_contracts_excluded_roles_call( - fixtures.API_CONTRACT_EXCLUSION_ROLE) - mocks.service_api_get_contracts_excluded_work_types_call( - fixtures.API_CONTRACT_EXCLUSION_WORK_TYPE) + mocks.service_api_get_company_alerts_call(fixtures.API_EMPTY) + mocks.service_api_get_contract_exclusion_sets_call( + fixtures.API_EMPTY) + mocks.service_api_get_contract_excluded_roles_call( + fixtures.API_EMPTY) + mocks.service_api_get_contract_excluded_work_types_call( + fixtures.API_EMPTY) diff --git a/djautotask/tests/test_sync.py b/djautotask/tests/test_sync.py index 90dfb8c..4d70750 100644 --- a/djautotask/tests/test_sync.py +++ b/djautotask/tests/test_sync.py @@ -1174,29 +1174,30 @@ def setUp(self): self._sync(self.fixture) def _call_api(self, return_data): - return mocks.service_api_get_contracts_exclusions_sets_call( + return mocks.service_api_get_contract_exclusion_sets_call( return_data) def _assert_fields(self, instance, object_data): self.assertEqual(instance.id, object_data['id']) self.assertEqual(instance.description, object_data['description']) - self.assertEqual(instance.isActive, object_data['isActive']) + self.assertEqual(instance.is_active, object_data['isActive']) self.assertEqual(instance.name, object_data['name']) class TestContractExclusionRoleSynchronizer(SynchronizerTestMixin, TestCase): synchronizer_class = sync.ContractExcludedRoleSynchronizer - model_class = models.ContractExcludeRoleTracker + model_class = models.ContractExcludedRoleTracker fixture = fixtures.API_CONTRACT_EXCLUSION_ROLE update_field = 'excluded_role_id' def setUp(self): super().setUp() - fixture_utils.init_contracts_exclusion_sets() + fixture_utils.init_roles() + fixture_utils.init_contract_exclusion_sets() self._sync(self.fixture) def _call_api(self, return_data): - return mocks.service_api_get_contracts_excluded_roles_call( + return mocks.service_api_get_contract_excluded_roles_call( return_data) def _assert_fields(self, instance, object_data): @@ -1216,19 +1217,20 @@ class TestContractExclusionWorkTypeSynchronizer(SynchronizerTestMixin, def setUp(self): super().setUp() - fixture_utils.init_contracts_exclusion_sets() + fixture_utils.init_billing_codes() + fixture_utils.init_contract_exclusion_sets() self._sync(self.fixture) def _call_api(self, return_data): - return mocks.service_api_get_contracts_excluded_work_types_call( + return mocks.service_api_get_contract_excluded_work_types_call( return_data) def _assert_fields(self, instance, object_data): self.assertEqual(instance.id, object_data['id']) self.assertEqual(instance.contract_exclusion_set.id, object_data['contractExclusionSetID']) - self.assertEqual(instance.excluded_work_type.id, object_data[ - 'excludedWorkTypeID']) + self.assertEqual(instance.excluded_work_type.id, + object_data['excludedWorkTypeID']) class TestCompanyAlertsSynchronizer(SynchronizerTestMixin, TestCase): From a26a9ccaaf2eec2e58012bffd9075c95e903d53c Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Wed, 30 Oct 2024 23:56:54 +0500 Subject: [PATCH 7/9] bump djautotask version --- djautotask/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djautotask/__init__.py b/djautotask/__init__.py index f648f2f..cfedf1b 100644 --- a/djautotask/__init__.py +++ b/djautotask/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -VERSION = (1, 6, 8, 'final') +VERSION = (1, 6, 9, 'final') # pragma: no cover if VERSION[-1] != "final": From 102af71c9560dd64e6d7087de2ab2bc6a47656bf Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Fri, 1 Nov 2024 13:41:29 +0500 Subject: [PATCH 8/9] migration merge --- djautotask/migrations/0120_merge_20241101_1316.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 djautotask/migrations/0120_merge_20241101_1316.py diff --git a/djautotask/migrations/0120_merge_20241101_1316.py b/djautotask/migrations/0120_merge_20241101_1316.py new file mode 100644 index 0000000..1b84884 --- /dev/null +++ b/djautotask/migrations/0120_merge_20241101_1316.py @@ -0,0 +1,14 @@ +# Generated by Django 4.2.16 on 2024-11-01 13:16 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('djautotask', '0118_contractexclusionset_and_more'), + ('djautotask', '0119_merge_20241024_1521'), + ] + + operations = [ + ] From 885c7ad38b0d1b90788a982776e574cfcd57e7fb Mon Sep 17 00:00:00 2001 From: Shoaib Sarwar Date: Fri, 1 Nov 2024 15:07:30 +0500 Subject: [PATCH 9/9] pep8 fixes --- djautotask/sync.py | 27 --------------------------- djautotask/tests/test_sync.py | 2 +- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/djautotask/sync.py b/djautotask/sync.py index df120ef..12e6b94 100644 --- a/djautotask/sync.py +++ b/djautotask/sync.py @@ -2005,33 +2005,6 @@ def active_ids(self): return active_ids -class CompanyAlertSynchronizer(BatchQueryMixin, Synchronizer): - client_class = api.CompanyAlertAPIClient - model_class = models.CompanyAlertTracker - condition_field_name = 'companyID' - last_updated_field = None - - related_meta = { - 'companyID': (models.Account, 'account'), - } - - def _assign_field_data(self, instance, object_data): - instance.id = object_data['id'] - instance.alert_text = object_data.get('alertText') - instance.alert_type = object_data.get('alertTypeID') - - self.set_relations(instance, object_data) - - return instance - - @property - def active_ids(self): - active_ids = models.Account.objects.all().\ - values_list('id', flat=True).order_by(self.lookup_key) - - return active_ids - - class ContractExclusionSetSynchronizer(Synchronizer): client_class = api.ContractExclusionSetAPIClient model_class = models.ContractExclusionSetTracker diff --git a/djautotask/tests/test_sync.py b/djautotask/tests/test_sync.py index 4d70750..e2e76d6 100644 --- a/djautotask/tests/test_sync.py +++ b/djautotask/tests/test_sync.py @@ -1230,7 +1230,7 @@ def _assert_fields(self, instance, object_data): self.assertEqual(instance.contract_exclusion_set.id, object_data['contractExclusionSetID']) self.assertEqual(instance.excluded_work_type.id, - object_data['excludedWorkTypeID']) + object_data['excludedWorkTypeID']) class TestCompanyAlertsSynchronizer(SynchronizerTestMixin, TestCase):