Repository: dotkom/onlineweb4

Issue:
Users who are retaking their third year are automatically set to first grade
<!-- If this is a security issue or information leakage (having access to something you (probably) shouldn't), please send an email rather than opening a public issue. -->

## What kind of an issue is this?

- Bug report
- Feature request


## What is the expected behaviour?
Users who are retaking their third year and apply for an extended membership should be put in the third grade. This should happen when using the dataporten application. 

## What is the current behaviour?

Users who are retaking their third year are automatically set to first grade when using the automatic application system.

<!-- if this is a bug report -->


## How do you reproduce this problem? 

<!-- if this is a bug report -->
<!-- provide steps to reproduce this problem, preferably in a bullet point list -->

* Be doing extra year of informatikk after third year. 
* Use automatic membership application to extend your membership. 
* Cry. 

## Other information

<!-- include screenshots if appropriate -->
<!-- add labels you see fit. please do not exaggerate. -->



Discussion:
When this was implemented it was intentionally left out to require manual intervention for people who are on their "3+" year(s). If this is not the desired behavior, however, feel free to change it.
As long as the students are still students at BIT they should automatically be approved. 

Resolving patch:
diff --git a/apps/dataporten/study/utils.py b/apps/dataporten/study/utils.py
--- a/apps/dataporten/study/utils.py
+++ b/apps/dataporten/study/utils.py
@@ -83,7 +83,8 @@ def get_bachelor_year(groups):
                 # If we don't know the end date, only add the years for the course.
                 years.append(get_add_years(group))
 
-    return max(years)
+    # Allows for users with extended bachelors to retain year 3 privileges.
+    return max(years) if max(years) <= 3 else 3
 
 
 def get_master_year(groups):


Test patch:
diff --git a/apps/dataporten/study/tests/data/3rd_grader_extended_1_year_2018.json b/apps/dataporten/study/tests/data/3rd_grader_extended_1_year_2018.json
new file mode 100644
--- /dev/null
+++ b/apps/dataporten/study/tests/data/3rd_grader_extended_1_year_2018.json
@@ -0,0 +1 @@
+[{"membership": {"notAfter": "2016-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Datamaskinprosjekt", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4295:1", "type": "fc:fs:emne"}, {"membership": {"displayName": "Student", "basic": "member", "fsroles": ["STUDENT"], "active": true}, "displayName": "Examen philosophicum for naturvitenskap og teknologi", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:EXPH0004:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-08-14T22:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Programmeringslab for Informatikk", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:IT1501:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2016-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Webutvikling", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:IT2810:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Informatikk prosjektarbeid I", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:IT1901:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-08-14T22:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Objektorientert programmering", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4100:1", "type": "fc:fs:emne"}, {"membership": {"displayName": "Student", "basic": "member", "fsroles": ["STUDENT"], "active": true}, "displayName": "Datamodellering og databasesystemer", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4145:1", "type": "fc:fs:emne"}, {"membership": {"displayName": "Student", "basic": "member", "fsroles": ["STUDENT"], "active": true}, "displayName": "Informasjonsteknologi, grunnkurs", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4110:1", "type": "fc:fs:emne"}, {"membership": {"displayName": "Student", "basic": "member", "fsroles": ["STUDENT"], "active": true}, "displayName": "Menneskemaskin-interaksjon", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4180:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Brukerkurs i matematikk A", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:MA0001:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Algoritmer og datastrukturer", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4120:1", "type": "fc:fs:emne"}, {"membership": {"displayName": "Student", "basic": "member", "fsroles": ["STUDENT"], "active": true}, "displayName": "Informatikk - bachelorstudium", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:prg:ntnu.no:BIT", "type": "fc:fs:prg", "url": "http://www.ntnu.no/studier/bit"}, {"membership": {"displayName": "Student", "basic": "member", "fsroles": ["STUDENT"], "active": true}, "displayName": "Introduksjon til helsefremming", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:HLS0001:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2016-08-14T22:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Programvareutvikling", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4140:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "HMS-kurs for 1. \u00e5rsstudenter", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:HMS0002:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Datamaskiner og digitalteknikk", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4160:1", "type": "fc:fs:emne"}, {"membership": {"displayName": "Student", "basic": "member", "fsroles": ["STUDENT"], "active": true}, "displayName": "Informatikk prosjektarbeid II", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:IT2901:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2016-08-14T22:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Operativsystemer", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TDT4186:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2016-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Sikkerhet og robusthet i IKT system", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TTM4185:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Prosjektplanlegging og styring", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TPK5100:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2017-08-14T22:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Entrepren\u00f8rskap - Venture CUP", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TI\u00d84250:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-08-14T22:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Kommunikasjon - Tjenester og nett", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:TTM4100:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-12-14T23:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Webteknologi", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:IT2805:1", "type": "fc:fs:emne"}, {"membership": {"notAfter": "2015-08-14T22:00:00Z", "basic": "member", "subjectRelations": "undervisning", "displayName": "Student", "active": true, "fsroles": ["STUDENT"]}, "displayName": "Element\u00e6r diskret matematikk", "parent": "fc:org:ntnu.no", "id": "fc:fs:fs:emne:ntnu.no:MA0301:1", "type": "fc:fs:emne"}, {"membership": {"title": ["fast ansatt"], "affiliation": ["employee", "member", "affiliate", "student"], "displayName": "Ansatt", "primaryAffiliation": "employee", "basic": "admin"}, "postalCode": "N-7491", "postalAddress": "N-7491 Trondheim $ NORWAY", "eduOrgHomePageURI": "http://www.ntnu.no/", "orgType": ["higher_education"], "street": "N-7491", "displayName": "NORGES TEKNISK-NATURVITENSKAPELIGE UNIVERSITET NTNU", "l": "Trondheim", "public": true, "id": "fc:org:ntnu.no", "norEduOrgAcronym": "NTNU", "facsimileTelephoneNumber": "+47 73595310", "eduOrgLegalName": "NORGES TEKNISK-NATURVITENSKAPELIGE UNIVERSITET NTNU", "mail": "orakel@ntnu.no", "labeledURI": "http://www.ntnu.no/", "norEduOrgUniqueIdentifier": "194000000", "norEduOrgNIN": "NO974767880", "telephoneNumber": "+47 73595000", "type": "fc:org"}, {"membership": {"primaryOrgUnit": false, "basic": "member"}, "parent": "fc:org:ntnu.no", "displayName": "Institutt for datateknologi og informatikk", "public": true, "id": "fc:org:ntnu.no:unit:631000", "type": "fc:orgunit"}, {"membership": {"primaryOrgUnit": true, "basic": "member"}, "parent": "fc:org:ntnu.no", "displayName": "IE-ADM", "public": true, "id": "fc:org:ntnu.no:unit:630100", "type": "fc:orgunit"}]
diff --git a/apps/dataporten/study/tests/utils_tests.py b/apps/dataporten/study/tests/utils_tests.py
--- a/apps/dataporten/study/tests/utils_tests.py
+++ b/apps/dataporten/study/tests/utils_tests.py
@@ -28,6 +28,7 @@
     PROJECT1_ACTIVE,
     PROJECT1_EXPIRED,
     PROJECT2_ACTIVE,
+    PROJECT2_EXPIRED,
     PVS_ACTIVE,
     load_course,
 )
@@ -145,6 +146,16 @@ def test_get_bachelor_year_3rd_grader_spring(self):
 
         self.assertEqual(3, get_bachelor_year(groups))
 
+    @freeze_time("2010-10-01 12:00")
+    def test_get_bachelor_year_3rd_grader_extended_year_fall(self):
+        groups = [
+            load_course(ITGK_EXPIRED, years_ago=3),
+            load_course(PROJECT1_EXPIRED, years_ago=2),
+            load_course(PROJECT2_EXPIRED, years_ago=1),
+        ]
+
+        self.assertEqual(3, get_bachelor_year(groups))
+
     @freeze_time("2010-10-01 12:00")
     def test_get_master_year_4th_grader_fall(self):
         groups = []
@@ -335,6 +346,18 @@ def test_find_study_3rd_grader_fall(self):
 
         self.assertEqual(3, get_year(GROUP_IDENTIFIERS["BACHELOR"], groups))
 
+    @freeze_time("2017-10-01 12:00")
+    def test_find_study_3rd_grader_extended_fall(self):
+        dumps_dir = os.path.join(DIR_NAME, "data")
+        fname = os.path.join(dumps_dir, "3rd_grader_extended_1_year_2018.json")
+        with open(fname, "r") as f:
+            groups = json.load(f)
+
+        field_of_study = get_field_of_study(groups)
+        self.assertEqual(FieldOfStudyType.BACHELOR, field_of_study)
+
+        self.assertEqual(3, get_year(GROUP_IDENTIFIERS["BACHELOR"], groups))
+
     @freeze_time("2017-10-01 12:00")
     def test_find_study_4th_grader_dbs_fall(self):
         dumps_dir = os.path.join(DIR_NAME, "data")