Skip to content

Commit 0324864

Browse files
authored
Merge pull request #1556 from uktrade/removal/interaction-contact-model-state
Remove Interaction.contact from state
2 parents b72af90 + da1cb12 commit 0324864

14 files changed

+57
-295
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The deprecated ``interaction_interaction.contact`` column is being prepared for removal and will shortly be removed. Please use the ``interaction_interaction_contacts`` table instead.

datahub/cleanup/management/commands/delete_old_records.py

-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ class Command(BaseCleanupCommand):
8282
# Contacts are not deleted if they have any related interactions, investment
8383
# projects, OMIS orders or OMIS quotes. We wait for those records to expire
8484
# before we delete the related contacts.
85-
Interaction._meta.get_field('contact').remote_field: (),
8685
Contact._meta.get_field('interactions'): (),
8786
Contact._meta.get_field('investment_projects'): (),
8887
Contact._meta.get_field('orders'): (),
-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datahub.core.test.factories import to_many_field
2-
from datahub.interaction.test.factories import CompanyInteractionFactory
32
from datahub.investment.project.test.factories import InvestmentProjectFactory
43

54

@@ -17,19 +16,3 @@ class ShallowInvestmentProjectFactory(InvestmentProjectFactory):
1716
def client_contacts(self):
1817
"""No client contacts."""
1918
return []
20-
21-
22-
class CompanyInteractionFactoryWithoutContacts(CompanyInteractionFactory):
23-
"""
24-
Same as CompanyInteractionFactory but with reduced dependencies
25-
so that we can test specific references without extra noise.
26-
27-
TODO: Remove once Interaction.contact has been removed.
28-
"""
29-
30-
contact = None
31-
32-
@to_many_field
33-
def contacts(self):
34-
"""Default to no contacts."""
35-
return []

datahub/cleanup/test/commands/test_delete_old_records.py

+1-13
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
ORDER_MODIFIED_ON_CUT_OFF,
2525
)
2626
from datahub.cleanup.query_utils import get_relations_to_delete
27-
from datahub.cleanup.test.commands.factories import CompanyInteractionFactoryWithoutContacts
2827
from datahub.company.test.factories import (
2928
CompanyFactory,
3029
ContactFactory,
@@ -226,18 +225,7 @@
226225
],
227226
'relations': [
228227
{
229-
'factory': CompanyInteractionFactoryWithoutContacts,
230-
'field': 'contact',
231-
'expired_objects_kwargs': [],
232-
'unexpired_objects_kwargs': [
233-
{
234-
'created_on': CONTACT_DELETE_BEFORE_DATETIME - relativedelta(days=1),
235-
'modified_on': CONTACT_DELETE_BEFORE_DATETIME - relativedelta(days=1),
236-
},
237-
],
238-
},
239-
{
240-
'factory': CompanyInteractionFactoryWithoutContacts,
228+
'factory': CompanyInteractionFactory,
241229
'field': 'contacts',
242230
'expired_objects_kwargs': [],
243231
'unexpired_objects_kwargs': [

datahub/cleanup/test/commands/test_delete_orphans.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111

1212
from datahub.cleanup.management.commands import delete_orphans
1313
from datahub.cleanup.query_utils import get_relations_to_delete
14-
from datahub.cleanup.test.commands.factories import (
15-
CompanyInteractionFactoryWithoutContacts,
16-
ShallowInvestmentProjectFactory,
17-
)
14+
from datahub.cleanup.test.commands.factories import ShallowInvestmentProjectFactory
1815
from datahub.company.test.factories import (
1916
CompanyFactory,
2017
ContactFactory,
@@ -47,8 +44,7 @@
4744
'company.Contact': {
4845
'factory': ContactFactory,
4946
'dependent_models': (
50-
(CompanyInteractionFactoryWithoutContacts, 'contact'),
51-
(CompanyInteractionFactoryWithoutContacts, 'contacts'),
47+
(CompanyInteractionFactory, 'contacts'),
5248
(OrderFactory, 'contact'),
5349
(QuoteFactory, 'accepted_by'),
5450
(InvestmentProjectFactory, 'client_contacts'),

datahub/interaction/admin.py

-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import json
22

33
from django.contrib import admin
4-
from django.db.transaction import atomic
54
from django.utils.html import format_html
65
from reversion.admin import VersionAdmin
76

@@ -121,7 +120,6 @@ class InteractionAdmin(BaseModelAdminMixin, VersionAdmin):
121120
'created_by',
122121
'modified_on',
123122
'modified_by',
124-
'contact',
125123
'source',
126124
)
127125

@@ -149,20 +147,6 @@ def pretty_source(self, obj):
149147

150148
pretty_source.short_description = 'source'
151149

152-
@atomic
153-
def save_model(self, request, obj, form, change):
154-
"""
155-
Saves the object, while also:
156-
- copying contacts to contact
157-
- copying dit_adviser and dit_team to dit_participants
158-
"""
159-
# TODO: Remove once the migration from contact to contacts is complete.
160-
if 'contacts' in form.cleaned_data:
161-
contacts = form.cleaned_data['contacts']
162-
obj.contact = contacts[0] if contacts else None
163-
164-
super().save_model(request, obj, form, change)
165-
166150
def changelist_view(self, request, extra_context=None):
167151
"""
168152
Change list view with additional data added to the context.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Generated by Django 2.1.7 on 2019-03-22 15:57
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('interaction', '0049_interaction_source'),
10+
]
11+
12+
operations = [
13+
migrations.SeparateDatabaseAndState(
14+
state_operations=[
15+
migrations.RemoveField(
16+
model_name='interaction',
17+
name='contact',
18+
),
19+
],
20+
),
21+
]

datahub/interaction/models.py

-10
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,8 @@ class Interaction(ArchivableModel, BaseModel):
169169
null=True,
170170
on_delete=models.CASCADE,
171171
)
172-
# TODO: contact is being replaced with contacts, and contact will be removed once the
173-
# migration to a to-many field is complete
174-
contact = models.ForeignKey(
175-
'company.Contact',
176-
related_name='+',
177-
blank=True,
178-
null=True,
179-
on_delete=models.CASCADE,
180-
)
181172
contacts = models.ManyToManyField(
182173
'company.Contact',
183-
# TODO: change related_name to interactions once this field has fully replaced contact
184174
related_name='%(class)ss',
185175
blank=True,
186176
)

datahub/interaction/serializers.py

-7
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,6 @@ def validate(self, data):
216216
if 'is_event' in data:
217217
del data['is_event']
218218

219-
# Copies the first contact specific to contact (for backwards compatibility with
220-
# anything consuming the database)
221-
# TODO Remove following deprecation period.
222-
if 'contacts' in data:
223-
contacts = data['contacts']
224-
data['contact'] = contacts[0] if contacts else None
225-
226219
# If dit_participants has been provided, this copies the first participant to
227220
# dit_adviser and dit_team (for backwards compatibility).
228221
# TODO Remove once dit_adviser and dit_team removed from the database.

datahub/interaction/test/factories.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ class InteractionFactoryBase(factory.django.DjangoModelFactory):
2222
created_by = factory.SubFactory(AdviserFactory)
2323
modified_by = factory.SubFactory(AdviserFactory)
2424
company = factory.SubFactory(CompanyFactory)
25-
contact = factory.SubFactory(
26-
ContactFactory,
27-
company=factory.SelfAttribute('..company'),
28-
)
2925
subject = factory.Faker('sentence', nb_words=8)
3026
date = factory.Faker('past_datetime', start_date='-5y', tzinfo=utc)
3127
notes = factory.Faker('paragraph', nb_sentences=10)
@@ -42,7 +38,7 @@ def contacts(self):
4238
4339
Defaults to the contact from the contact field.
4440
"""
45-
return [self.contact] if self.contact else []
41+
return [ContactFactory(company=self.company)] if self.company else []
4642

4743
@to_many_field
4844
def dit_participants(self):

datahub/interaction/test/test_admin.py

+5-138
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,15 @@
1-
from uuid import uuid4
2-
31
import pytest
42
from django.contrib.admin import site
5-
from django.contrib.admin.templatetags.admin_urls import admin_urlname
6-
from django.urls import reverse
7-
from rest_framework import status
83

9-
from datahub.company.test.factories import CompanyFactory, ContactFactory
10-
from datahub.core.admin import get_change_url
11-
from datahub.core.test_utils import AdminTestMixin, random_obj_for_model
4+
from datahub.company.test.factories import ContactFactory
5+
from datahub.core.test_utils import AdminTestMixin
126
from datahub.interaction.admin import InteractionAdmin
13-
from datahub.interaction.models import CommunicationChannel, Interaction
7+
from datahub.interaction.models import Interaction
148
from datahub.interaction.test.factories import CompanyInteractionFactory
15-
from datahub.metadata.models import Service, Team
16-
17-
18-
class TestInteractionAdminContacts(AdminTestMixin):
19-
"""
20-
Tests for the contacts and contact logic in interaction admin.
21-
22-
TODO: The app and update tests will be removed once the migration from contact to
23-
contacts is complete.
24-
"""
25-
26-
def test_add(self):
27-
"""Test that adding an interaction also sets the contact field."""
28-
company = CompanyFactory()
29-
contacts = ContactFactory.create_batch(2, company=company)
30-
communication_channel = random_obj_for_model(CommunicationChannel)
31-
32-
url = reverse(admin_urlname(Interaction._meta, 'add'))
33-
data = {
34-
'id': uuid4(),
35-
'kind': Interaction.KINDS.interaction,
36-
'status': Interaction.STATUSES.complete,
37-
'communication_channel': communication_channel.pk,
38-
'subject': 'whatever',
39-
'date_0': '2018-01-01',
40-
'date_1': '00:00:00',
41-
'dit_adviser': self.user.pk,
42-
'company': company.pk,
43-
'contacts': [contact.pk for contact in contacts],
44-
'service': random_obj_for_model(Service).pk,
45-
'dit_team': random_obj_for_model(Team).pk,
46-
'was_policy_feedback_provided': False,
47-
'dit_participants-TOTAL_FORMS': 0,
48-
'dit_participants-INITIAL_FORMS': 0,
49-
'dit_participants-MAX_NUM_FORMS': 0,
50-
'dit_participants-MIN_NUM_FORMS': 0,
51-
}
52-
response = self.client.post(url, data, follow=True)
53-
54-
assert response.status_code == status.HTTP_200_OK
55-
56-
assert Interaction.objects.count() == 1
57-
interaction = Interaction.objects.first()
58-
59-
assert interaction.contact == contacts[0]
60-
assert set(interaction.contacts.all()) == set(contacts)
61-
62-
def test_update_contact_to_non_null(self):
63-
"""
64-
Test that updating an interaction with a value in contacts also sets the contact field.
65-
"""
66-
interaction = CompanyInteractionFactory()
67-
new_contacts = ContactFactory.create_batch(2, company=interaction.company)
68-
69-
url = get_change_url(interaction)
70-
data = {
71-
# Unchanged values
72-
'id': interaction.pk,
73-
'kind': Interaction.KINDS.interaction,
74-
'status': Interaction.STATUSES.complete,
75-
'communication_channel': interaction.communication_channel.pk,
76-
'subject': interaction.subject,
77-
'date_0': interaction.date.date().isoformat(),
78-
'date_1': interaction.date.time().isoformat(),
79-
'dit_adviser': interaction.dit_adviser.pk,
80-
'company': interaction.company.pk,
81-
'service': interaction.service.pk,
82-
'dit_team': interaction.dit_team.pk,
83-
'was_policy_feedback_provided': interaction.was_policy_feedback_provided,
84-
'policy_feedback_notes': interaction.policy_feedback_notes,
85-
'policy_areas': [],
86-
'policy_issue_types': [],
87-
'event': '',
88-
'dit_participants-TOTAL_FORMS': 0,
89-
'dit_participants-INITIAL_FORMS': 0,
90-
'dit_participants-MAX_NUM_FORMS': 0,
91-
'dit_participants-MIN_NUM_FORMS': 0,
92-
'dit_participants-0-id': interaction.dit_participants.first().pk,
93-
'dit_participants-0-interaction': interaction.pk,
94-
95-
# Changed values
96-
'contacts': [contact.pk for contact in new_contacts],
97-
}
98-
response = self.client.post(url, data, follow=True)
99-
100-
assert response.status_code == status.HTTP_200_OK
101-
102-
interaction.refresh_from_db()
103-
assert interaction.contact == new_contacts[0]
104-
assert set(interaction.contacts.all()) == set(new_contacts)
105-
106-
def test_update_contact_to_null(self):
107-
"""Test that removing all contacts from an interaction clears the contact field."""
108-
interaction = CompanyInteractionFactory()
109-
110-
url = get_change_url(interaction)
111-
data = {
112-
# Unchanged values
113-
'id': interaction.pk,
114-
'kind': Interaction.KINDS.interaction,
115-
'status': Interaction.STATUSES.complete,
116-
'communication_channel': interaction.communication_channel.pk,
117-
'subject': interaction.subject,
118-
'date_0': interaction.date.date().isoformat(),
119-
'date_1': interaction.date.time().isoformat(),
120-
'dit_adviser': interaction.dit_adviser.pk,
121-
'company': interaction.company.pk,
122-
'service': interaction.service.pk,
123-
'dit_team': interaction.dit_team.pk,
124-
'was_policy_feedback_provided': interaction.was_policy_feedback_provided,
125-
'policy_feedback_notes': interaction.policy_feedback_notes,
126-
'policy_areas': [],
127-
'policy_issue_types': [],
128-
'event': '',
129-
'dit_participants-TOTAL_FORMS': 0,
130-
'dit_participants-INITIAL_FORMS': 0,
131-
'dit_participants-MAX_NUM_FORMS': 0,
132-
'dit_participants-MIN_NUM_FORMS': 0,
133-
'dit_participants-0-id': interaction.dit_participants.first().pk,
134-
'dit_participants-0-interaction': interaction.pk,
135-
136-
# Changed values
137-
'contacts': [],
138-
}
139-
response = self.client.post(url, data=data, follow=True)
1409

141-
assert response.status_code == status.HTTP_200_OK
14210

143-
interaction.refresh_from_db()
144-
assert interaction.contact is None
145-
assert interaction.contacts.count() == 0
11+
class TestInteractionAdmin(AdminTestMixin):
12+
"""Tests for interaction admin."""
14613

14714
@pytest.mark.parametrize(
14815
'num_contacts,expected_display_value',

0 commit comments

Comments
 (0)