diff --git a/djautotask/__init__.py b/djautotask/__init__.py index d390577..f648f2f 100644 --- a/djautotask/__init__.py +++ b/djautotask/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -VERSION = (1, 6, 7, 'final') +VERSION = (1, 6, 8, 'final') # pragma: no cover if VERSION[-1] != "final": diff --git a/djautotask/admin.py b/djautotask/admin.py index a8f737d..88ba7bf 100644 --- a/djautotask/admin.py +++ b/djautotask/admin.py @@ -397,3 +397,8 @@ class ProjectUDFAdmin(admin.ModelAdmin): @admin.register(models.ProjectNoteType) class ProjectNoteTypeAdmin(admin.ModelAdmin): list_display = ('id', 'label') + + +@admin.register(models.CompanyAlert) +class CompanyAlertsAdmin(admin.ModelAdmin): + list_display = ('id', 'alert_text', 'alert_type', 'account') diff --git a/djautotask/api.py b/djautotask/api.py index 76a6a2f..a64826c 100644 --- a/djautotask/api.py +++ b/djautotask/api.py @@ -782,6 +782,10 @@ class TicketCategoriesAPIClient(AutotaskAPIClient): API = 'TicketCategories' +class CompanyAlertAPIClient(AutotaskAPIClient): + API = 'CompanyAlerts' + + class ProjectNotesAPIClient(AutotaskAPIClient): API = 'ProjectNotes' diff --git a/djautotask/management/commands/atsync.py b/djautotask/management/commands/atsync.py index ee05945..ccbfbe9 100644 --- a/djautotask/management/commands/atsync.py +++ b/djautotask/management/commands/atsync.py @@ -121,6 +121,11 @@ def __init__(self, *args, **kwargs): sync.ServiceCallTicketResourceSynchronizer, _('Service Call Ticket Resource') ), + ( + 'company_alert', + sync.CompanyAlertSynchronizer, + _('Company Alert') + ), ( 'service_call_task_resource', sync.ServiceCallTaskResourceSynchronizer, diff --git a/djautotask/migrations/0118_alter_tasktypetracker_table_companyalert_and_more.py b/djautotask/migrations/0118_alter_tasktypetracker_table_companyalert_and_more.py new file mode 100644 index 0000000..3186140 --- /dev/null +++ b/djautotask/migrations/0118_alter_tasktypetracker_table_companyalert_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 4.2.16 on 2024-10-08 02:10 + +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.AlterModelTable( + name='tasktypetracker', + table=None, + ), + migrations.CreateModel( + name='CompanyAlert', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('alert_text', models.TextField(blank=True, max_length=8000, null=True)), + ('alert_type', models.IntegerField(blank=True, null=True)), + ('account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='alerts', to='djautotask.account')), + ], + ), + migrations.CreateModel( + name='CompanyAlertTracker', + fields=[ + ], + options={ + 'db_table': 'djautotask_companyalert', + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('djautotask.companyalert',), + ), + ] diff --git a/djautotask/migrations/0119_merge_20241024_1521.py b/djautotask/migrations/0119_merge_20241024_1521.py new file mode 100644 index 0000000..5ca01ba --- /dev/null +++ b/djautotask/migrations/0119_merge_20241024_1521.py @@ -0,0 +1,14 @@ +# Generated by Django 4.2.16 on 2024-10-24 15:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('djautotask', '0118_alter_tasktypetracker_table_companyalert_and_more'), + ('djautotask', '0118_alter_ticket_due_date_time'), + ] + + operations = [ + ] diff --git a/djautotask/models.py b/djautotask/models.py index 01f483b..5843b31 100644 --- a/djautotask/models.py +++ b/djautotask/models.py @@ -1125,6 +1125,20 @@ def __str__(self): return self.name +class CompanyAlert(models.Model): + TICKET_EDIT_ALERT_TYPE = 3 + + alert_text = models.TextField(blank=True, null=True, max_length=8000) + alert_type = models.IntegerField(blank=True, null=True) + account = models.ForeignKey( + 'Account', blank=True, null=True, on_delete=models.SET_NULL, + related_name='alerts' + ) + + def __str__(self): + return self.alert_text + + class TicketUDF(BaseUDF): pass @@ -1526,4 +1540,11 @@ class TaskTypeTracker(TaskType): class Meta: proxy = True - db_table = 'djautotask_tasktype' + + +class CompanyAlertTracker(CompanyAlert): + tracker = FieldTracker() + + class Meta: + proxy = True + db_table = 'djautotask_companyalert' diff --git a/djautotask/sync.py b/djautotask/sync.py index 4297d23..4c93870 100644 --- a/djautotask/sync.py +++ b/djautotask/sync.py @@ -1976,6 +1976,33 @@ def _assign_field_data(self, instance, json_data): return instance +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 NoteTypeSynchronizer(PicklistSynchronizer): # Ticket note types are including task note types, and there are other # note types currently not used. e.g. project note types diff --git a/djautotask/tests/fixture_utils.py b/djautotask/tests/fixture_utils.py index 8a39854..5a9e324 100644 --- a/djautotask/tests/fixture_utils.py +++ b/djautotask/tests/fixture_utils.py @@ -376,3 +376,10 @@ def init_service_call_task_resources(): fixtures.API_SERVICE_CALL_TASK_RESOURCE) synchronizer = sync.ServiceCallTaskResourceSynchronizer() return synchronizer.sync() + + +def init_company_alerts(): + models.CompanyAlert.objects.all().delete() + mocks.service_api_get_company_alerts_call(fixtures.API_COMPANY_ALERTS) + synchronizer = sync.CompanyAlertSynchronizer() + return synchronizer.sync() diff --git a/djautotask/tests/fixtures.py b/djautotask/tests/fixtures.py index 757e686..29c4820 100644 --- a/djautotask/tests/fixtures.py +++ b/djautotask/tests/fixtures.py @@ -1434,3 +1434,15 @@ "items": API_TICKET_ITEMS, "pageDetails": API_PAGE_DETAILS } + +API_COMPANY_ALERT_ITEM = { + "id": 1, + "alertText": "Find me here: Account Detail Screen > Edit Account > Alerts tab.", + "alertTypeID": 1, + "companyID": 174 +} +API_COMPANY_ALERT_ITEMS = [API_COMPANY_ALERT_ITEM] +API_COMPANY_ALERTS = { + "items": API_COMPANY_ALERT_ITEMS, + "pageDetails": API_PAGE_DETAILS +} \ No newline at end of file diff --git a/djautotask/tests/mocks.py b/djautotask/tests/mocks.py index afb41ba..09bac79 100644 --- a/djautotask/tests/mocks.py +++ b/djautotask/tests/mocks.py @@ -49,6 +49,11 @@ def service_api_get_contacts_call(return_value): return create_mock_call(method_name, return_value) +def service_api_get_company_alerts_call(return_value): + method_name = 'djautotask.api.CompanyAlertAPIClient.get' + return create_mock_call(method_name, return_value) + + def service_api_get_contracts_call(return_value): method_name = 'djautotask.api.ContractsAPIClient.get' return create_mock_call(method_name, return_value) diff --git a/djautotask/tests/test_commands.py b/djautotask/tests/test_commands.py index f6aafe1..fc16d94 100644 --- a/djautotask/tests/test_commands.py +++ b/djautotask/tests/test_commands.py @@ -717,6 +717,19 @@ def setUp(self): fixture_utils.init_task_predecessors() +class TestSyncCompanyAlertsCommand(AbstractBaseSyncTest, TestCase): + args = ( + mocks.service_api_get_company_alerts_call, + fixtures.API_COMPANY_ALERTS, + 'company_alert', + ) + + def setUp(self): + super().setUp() + fixture_utils.init_accounts() + fixture_utils.init_company_alerts() + + class TestSyncAllCommand(TestCase): def setUp(self): @@ -772,6 +785,7 @@ def setUp(self): TestSyncAccountLocationCommand, TestSyncTaskPredecessor, TestSyncContactCommand, + TestSyncCompanyAlertsCommand, ] self.test_args = [] @@ -853,6 +867,7 @@ def test_full_sync(self): 'service_call_task_resource': models.ServiceCallTaskResource, 'task_predecessor': models.TaskPredecessor, 'contact': models.Contact, + 'company_alert': models.CompanyAlert, } run_sync_command() pre_full_sync_counts = {} @@ -954,6 +969,8 @@ def _call_service_api(self): fixtures.API_SERVICE_CALL_TASK_RESOURCE) mocks.service_api_get_task_predecessors_call( fixtures.API_TASK_PREDECESSOR) + mocks.service_api_get_company_alerts_call( + fixtures.API_COMPANY_ALERTS) def _call_empty_service_api(self): mocks.service_api_get_ticket_udf_call(fixtures.API_EMPTY_FIELDS) @@ -1008,3 +1025,4 @@ 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) diff --git a/djautotask/tests/test_sync.py b/djautotask/tests/test_sync.py index cc1066e..72427e9 100644 --- a/djautotask/tests/test_sync.py +++ b/djautotask/tests/test_sync.py @@ -1161,6 +1161,28 @@ def _assert_fields(self, instance, object_data): self.assertEqual(instance.account.id, object_data['companyID']) +class TestCompanyAlertsSynchronizer(SynchronizerTestMixin, TestCase): + synchronizer_class = sync.CompanyAlertSynchronizer + model_class = models.CompanyAlertTracker + fixture = fixtures.API_COMPANY_ALERTS + update_field = 'alert_text' + + def setUp(self): + super().setUp() + fixture_utils.init_accounts() + fixture_utils.init_company_alerts() + self._sync(self.fixture) + + def _call_api(self, return_data): + return mocks.service_api_get_company_alerts_call(return_data) + + def _assert_fields(self, instance, object_data): + self.assertEqual(instance.id, object_data['id']) + self.assertEqual(instance.alert_text, object_data['alertText']) + self.assertEqual(instance.alert_type, object_data['alertTypeID']) + self.assertEqual(instance.account.id, object_data['companyID']) + + class TestServiceCallSynchronizer(SynchronizerTestMixin, TestCase): synchronizer_class = sync.ServiceCallSynchronizer model_class = models.ServiceCallTracker diff --git a/makemigrations.py b/makemigrations.py index 6139489..b957bd3 100755 --- a/makemigrations.py +++ b/makemigrations.py @@ -1,5 +1,6 @@ #!/usr/bin/env python import django +import argparse from django.conf import settings from django.core.management import call_command @@ -12,13 +13,18 @@ ) -def makemigrations(): +def makemigrations(merge): django.setup() - # If a migration ever says to run makemigrations --merge, run this: - # call_command('makemigrations', 'djautotask', '--merge') - # (And consider adding --merge to this script.) - call_command('makemigrations', 'djautotask') + if merge: + call_command('makemigrations', 'djautotask', '--merge') + else: + call_command('makemigrations', 'djautotask') if __name__ == '__main__': - makemigrations() + parser = argparse.ArgumentParser( + description='Run makemigrations with optional --merge.') + parser.add_argument( + '--merge', action='store_true', help='Include the --merge option') + args = parser.parse_args() + makemigrations(args.merge)