diff --git a/lego/apps/companies/fixtures/development_companies.yaml b/lego/apps/companies/fixtures/development_companies.yaml index c4f21f508..49162fa10 100644 --- a/lego/apps/companies/fixtures/development_companies.yaml +++ b/lego/apps/companies/fixtures/development_companies.yaml @@ -31,7 +31,6 @@ fields: name: 'BEKK' description: 'Bekk Consulting AS er et norsk konsulentselskap. Vi gjennomfører prosjekter for store private og offentlige virksomheter innen strategisk rådgivning, utvikling av IT-systemer og design av digitale tjenester. Vi er i dag over 370 fagpersoner.' - student_contact: 1 phone: '+47 90909090' website: 'bekk.no' payment_mail: faktura@bekk.no @@ -43,7 +42,6 @@ pk: 2 fields: name: 'Facebook' - student_contact: 2 phone: '123 45 678' - model: companies.Company @@ -51,7 +49,6 @@ fields: name: 'Itera' description: 'Itera er et kommunikasjons- og teknologiselskap. Vi leverer tjenester innen rådgivning og strategi, design og utvikling, drift og forvaltning. Vi er engasjerte fagspesialister som jobber i tverrfaglige team fordi vi vet at vi med ulike faglige ståsteder avdekker helt nye muligheter og løsninger som gir verdi til kundene våre.' - student_contact: 3 phone: '' # Company 1 diff --git a/lego/apps/companies/fixtures/test_companies.yaml b/lego/apps/companies/fixtures/test_companies.yaml index f14e77807..af8f9ccff 100644 --- a/lego/apps/companies/fixtures/test_companies.yaml +++ b/lego/apps/companies/fixtures/test_companies.yaml @@ -14,7 +14,6 @@ pk: 1 fields: name: 'Facebook' - student_contact: 2 phone: '123 45 678' - model: companies.Company @@ -22,7 +21,6 @@ fields: name: 'Itera' description: 'Itera er et kommunikasjons- og teknologiselskap. Vi leverer tjenester innen rådgivning og strategi, design og utvikling, drift og forvaltning. Vi er engasjerte fagspesialister som jobber i tverrfaglige team fordi vi vet at vi med ulike faglige ståsteder avdekker helt nye muligheter og løsninger som gir verdi til kundene våre.' - student_contact: 3 phone: '' - model: companies.Company @@ -30,7 +28,6 @@ fields: name: 'Webkom' description: 'Webkom er webkom' - student_contact: 3 phone: '' - model: companies.SemesterStatus @@ -40,6 +37,21 @@ company: 1 contacted_status: ['interested'] +- model: companies.StudentCompanyContact + pk: 1 + fields: + company: 1 + student: 1 + semester: 1 + +- model: companies.StudentCompanyContact + pk: 2 + fields: + company: 1 + student: 2 + semester: 2 + + - model: companies.CompanyContact pk: 1 fields: diff --git a/lego/apps/companies/migrations/0029_remove_company_previous_contacts_and_more.py b/lego/apps/companies/migrations/0029_remove_company_previous_contacts_and_more.py new file mode 100644 index 000000000..bc3e80546 --- /dev/null +++ b/lego/apps/companies/migrations/0029_remove_company_previous_contacts_and_more.py @@ -0,0 +1,105 @@ +# Generated by Django 4.0.10 on 2024-09-18 18:58 + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("companies", "0028_alter_companyinterest_other_offers"), + ] + + operations = [ + migrations.RemoveField( + model_name="company", + name="previous_contacts", + ), + migrations.RemoveField( + model_name="company", + name="student_contact", + ), + migrations.CreateModel( + name="StudentCompanyContact", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "created_at", + models.DateTimeField( + db_index=True, default=django.utils.timezone.now, editable=False + ), + ), + ( + "updated_at", + models.DateTimeField( + default=django.utils.timezone.now, editable=False + ), + ), + ( + "deleted", + models.BooleanField(db_index=True, default=False, editable=False), + ), + ( + "company", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="student_contacts", + to="companies.company", + ), + ), + ( + "created_by", + models.ForeignKey( + default=None, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="%(class)s_created", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "semester", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="student_contacts", + to="companies.semester", + ), + ), + ( + "student", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="contact_for_companies", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "updated_by", + models.ForeignKey( + default=None, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="%(class)s_updated", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + "default_manager_name": "objects", + }, + ), + ] diff --git a/lego/apps/companies/models.py b/lego/apps/companies/models.py index e97c830c4..37b799ed5 100644 --- a/lego/apps/companies/models.py +++ b/lego/apps/companies/models.py @@ -42,10 +42,6 @@ class Meta: class Company(BasisModel): name = models.CharField(max_length=100) - student_contact = models.ForeignKey( - User, related_name="companies", null=True, on_delete=models.SET_NULL - ) - previous_contacts = models.ManyToManyField(User) description = models.TextField(blank=True) phone = models.CharField(max_length=100, blank=True) @@ -72,6 +68,18 @@ def __str__(self) -> str: return self.name +class StudentCompanyContact(BasisModel): + company = models.ForeignKey( + Company, related_name="student_contacts", on_delete=models.CASCADE + ) + student = models.ForeignKey( + User, related_name="contact_for_companies", on_delete=models.CASCADE + ) + semester = models.ForeignKey( + Semester, related_name="student_contacts", on_delete=models.CASCADE + ) + + class CompanyFile(models.Model): company = models.ForeignKey(Company, related_name="files", on_delete=models.CASCADE) file = FileField() diff --git a/lego/apps/companies/serializers.py b/lego/apps/companies/serializers.py index 3f978f47e..3e1d3f588 100644 --- a/lego/apps/companies/serializers.py +++ b/lego/apps/companies/serializers.py @@ -12,10 +12,9 @@ CompanyInterest, Semester, SemesterStatus, + StudentCompanyContact, ) from lego.apps.files.fields import FileField, ImageField -from lego.apps.users.fields import PublicUserField -from lego.apps.users.models import User from lego.utils.serializers import BasisModelSerializer @@ -36,6 +35,12 @@ def create(self, validated_data): return super().create(validated_data) +class StudentCompanyContactSerializer(BasisModelSerializer): + class Meta: + model = StudentCompanyContact + fields = ("id", "company_id", "student_id", "semester_id") + + class SemesterStatusDetailSerializer(SemesterStatusSerializer): contract = FileField(required=False, allow_null=True) statistics = FileField(required=False, allow_null=True) @@ -128,8 +133,8 @@ class Meta: class CompanyAdminListSerializer(BasisModelSerializer): - semester_statuses = SemesterStatusSerializer(many=True, read_only=True) - student_contact = PublicUserField(required=False, queryset=User.objects.all()) + semester_statuses = serializers.SerializerMethodField() + student_contacts = serializers.SerializerMethodField() class Meta: model = Company @@ -137,11 +142,35 @@ class Meta: "id", "name", "semester_statuses", - "student_contact", + "student_contacts", "admin_comment", "active", ) + def get_student_contacts(self, obj): + semester_id = self.context.get("semester_id") + + if semester_id is None: + queryset = StudentCompanyContact.objects.filter(company=obj) + else: + queryset = StudentCompanyContact.objects.filter( + company=obj, semester_id=semester_id + ) + + return StudentCompanyContactSerializer(queryset, many=True).data + + def get_semester_statuses(self, obj): + semester_id = self.context.get("semester_id") + + if semester_id is None: + queryset = SemesterStatus.objects.filter(company=obj) + else: + queryset = SemesterStatus.objects.filter( + company=obj, semester_id=semester_id + ) + + return SemesterStatusSerializer(queryset, many=True).data + class CompanyDetailSerializer(BasisModelSerializer): logo = ImageField(required=False, options={"height": 500}) @@ -178,9 +207,7 @@ class CompanyAdminDetailSerializer(BasisModelSerializer): comments = CommentSerializer(read_only=True, many=True) content_target = CharField(read_only=True) - student_contact = PublicUserField( - required=False, allow_null=True, queryset=User.objects.all() - ) + student_contacts = StudentCompanyContactSerializer(many=True, read_only=True) semester_statuses = SemesterStatusDetailSerializer(many=True, read_only=True) company_contacts = CompanyContactSerializer(many=True, read_only=True) @@ -192,7 +219,7 @@ class Meta: fields = ( "id", "name", - "student_contact", + "student_contacts", "description", "phone", "company_type", diff --git a/lego/apps/companies/tests/test_companies_admin_api.py b/lego/apps/companies/tests/test_companies_admin_api.py index 286f2028b..54946f3f3 100644 --- a/lego/apps/companies/tests/test_companies_admin_api.py +++ b/lego/apps/companies/tests/test_companies_admin_api.py @@ -67,6 +67,19 @@ def test_with_bedkom_user(self): company_response = self.client.get(_get_bdb_list_url()) self.assertEqual(company_response.status_code, status.HTTP_200_OK) self.assertEqual(len(company_response.json()["results"]), 3) + self.assertEqual( + len(company_response.json()["results"][0]["studentContacts"]), 2 + ) + + def test_with_semester_query(self): + AbakusGroup.objects.get(name="Bedkom").add_user(self.abakus_user) + self.client.force_authenticate(self.abakus_user) + company_response = self.client.get(_get_bdb_list_url(), {"semester_id": 1}) + self.assertEqual(company_response.status_code, status.HTTP_200_OK) + self.assertEqual(len(company_response.json()["results"]), 3) + self.assertEqual( + len(company_response.json()["results"][0]["studentContacts"]), 1 + ) class RetrieveCompaniesTestCase(BaseAPITestCase): diff --git a/lego/apps/companies/views.py b/lego/apps/companies/views.py index 8f612a1a2..70b498bfb 100644 --- a/lego/apps/companies/views.py +++ b/lego/apps/companies/views.py @@ -45,14 +45,19 @@ class AdminCompanyViewSet(AllowedPermissionsMixin, viewsets.ModelViewSet): - queryset = ( - Company.objects.all() - .prefetch_related("semester_statuses", "files") - .select_related("student_contact") - ) + queryset = Company.objects.all().prefetch_related("semester_statuses", "files") pagination_class = None permission_handler = CompanyAdminPermissionHandler() + def get_serializer_context(self): + context = super().get_serializer_context() + + if self.action == "list": + semester_id = self.request.query_params.get("semester_id", None) + context.update({"semester_id": semester_id}) + + return context + def get_serializer_class(self): if self.action == "list": return CompanyAdminListSerializer