Codebeispiele: Ausgangszustand
This commit is contained in:
		
							
								
								
									
										101
									
								
								h1wsutils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								h1wsutils.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # | ||||||
|  | # @author Dr. Wolfgang Wiedermann    | ||||||
|  | # | ||||||
|  | # Webservice-Handling für HISinOne | ||||||
|  | # | ||||||
|  | # Abhängigkeiten: | ||||||
|  | # * zeep (pip install zeep oder python -m pip install zeep) | ||||||
|  | # | ||||||
|  | # Doku der HIS zu Webservices im Bereich Bewerbung:  | ||||||
|  | # * https://wiki.his.de/mediawiki/index.php/APP-Webservices-HISinOne | ||||||
|  | # | ||||||
|  |  | ||||||
|  | class H1WebServiceUtils: | ||||||
|  |     # | ||||||
|  |     # Attribute  | ||||||
|  |     # | ||||||
|  |     user = None | ||||||
|  |     password = None | ||||||
|  |     host = "localhost" | ||||||
|  |     wsdl_folder = "wsdl" | ||||||
|  |     service_names = [] | ||||||
|  |     proxies = {} | ||||||
|  |  | ||||||
|  |     # | ||||||
|  |     # Konstruktor | ||||||
|  |     # | ||||||
|  |     def __init__(self, user, password, host, wsdl_folder, services): | ||||||
|  |         self.user = user | ||||||
|  |         self.password = password | ||||||
|  |         self.host = host | ||||||
|  |         self.wsdl_folder = wsdl_folder | ||||||
|  |         self.service_names = services | ||||||
|  |  | ||||||
|  |     # | ||||||
|  |     # Einzelne WSDL laden und relevante Teile ersetzen | ||||||
|  |     # | ||||||
|  |     def __download_wsdl(self, wsdl): | ||||||
|  |         global HOST | ||||||
|  |         import urllib.request | ||||||
|  |         import re | ||||||
|  |  | ||||||
|  |         txt = "" | ||||||
|  |         new_file = "{0}/{1}.wsdl".format(self.wsdl_folder, wsdl) | ||||||
|  |         urllib.request.urlretrieve("https://{0}.kdv-fh-bayern.de/qisserver/services2/{1}?wsdl".format(self.host, wsdl), new_file) | ||||||
|  |  | ||||||
|  |         with open(new_file) as f: | ||||||
|  |             txt = f.read() | ||||||
|  |             txt = re.sub(r"http://[^/]+:8080/", ("https://{0}.kdv-fh-bayern.de/".format(self.host)), txt) | ||||||
|  |             txt = re.sub(r"https://[^/]+:8443/", ("https://{0}.kdv-fh-bayern.de/".format(self.host)), txt) | ||||||
|  |             txt = re.sub(r"http://localhost/", ("https://{0}.kdv-fh-bayern.de/".format(self.host)), txt) | ||||||
|  |         with open(new_file, "w+") as f: | ||||||
|  |             f.write(txt) | ||||||
|  |  | ||||||
|  |     # | ||||||
|  |     # WSDL-Beschreibung von HISinOne laden | ||||||
|  |     # | ||||||
|  |     def download_wsdls(self): | ||||||
|  |         import os  | ||||||
|  |         # Falls nötig, Ordner für WSDL-Dateien anlegen | ||||||
|  |         if not os.path.isdir(self.wsdl_folder): | ||||||
|  |             os.makedirs(self.wsdl_folder) | ||||||
|  |         # Falls nötig, WSDL-Dateien laden         | ||||||
|  |         for service in self.service_names: | ||||||
|  |             if not os.path.isfile("{0}/{1}.wsdl".format(self.wsdl_folder, service)): | ||||||
|  |                 self.__download_wsdl(service) | ||||||
|  |  | ||||||
|  |     # | ||||||
|  |     # Proxy für einzelnen Service laden | ||||||
|  |     # | ||||||
|  |     def get_proxy(self, service):       | ||||||
|  |         from zeep import Client | ||||||
|  |         from zeep.wsse.username import UsernameToken | ||||||
|  |  | ||||||
|  |         if service not in self.proxies.keys():             | ||||||
|  |             svc = Client("./{0}/{1}.wsdl".format(self.wsdl_folder, service), wsse=UsernameToken(self.user, self.password)) | ||||||
|  |             self.proxies[service] = svc | ||||||
|  |         return self.proxies[service] | ||||||
|  |          | ||||||
|  |  | ||||||
|  |     # | ||||||
|  |     # Typ aus WSDL-Definition laden | ||||||
|  |     # | ||||||
|  |     def get_type(self, service, typename): | ||||||
|  |         return self.proxies[service].get_type("ns0:{0}".format(typename)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     # | ||||||
|  |     # Passwort ermitteln (entweder erfragen oder aus Passwort-Save) | ||||||
|  |     # | ||||||
|  |     def get_password(appname, username): | ||||||
|  |         import getpass | ||||||
|  |         import keyring | ||||||
|  |  | ||||||
|  |         # Passwort sinnvoll behandeln! | ||||||
|  |         if keyring.get_password(appname, username) is None: | ||||||
|  |             print("Bitte geben Sie das Passwort für den Benutzer {0} an.".format(username)) | ||||||
|  |             p = getpass.getpass() | ||||||
|  |             keyring.set_password(appname, username, p) | ||||||
|  |  | ||||||
|  |         return keyring.get_password(appname, username) | ||||||
							
								
								
									
										219
									
								
								incomings_to_stu.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								incomings_to_stu.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,219 @@ | |||||||
|  | from datetime import datetime | ||||||
|  | from h1wsutils import H1WebServiceUtils | ||||||
|  |  | ||||||
|  | # Some configuration Data statically added (for examples only!) | ||||||
|  | USER        = "mo_webservice_user" | ||||||
|  | PASSWD      = "geheim" | ||||||
|  | HOST        = "hisinone-7350-s" | ||||||
|  | WSDL_FOLDER = "wsdl" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SERVICES = ( | ||||||
|  |     "CourseOfStudyService", | ||||||
|  |     "PersonService",  | ||||||
|  |     "PersonAddressService",    | ||||||
|  |     "StudentService201812", | ||||||
|  |     "StudentService", | ||||||
|  |     "KeyvalueService" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | h1util = H1WebServiceUtils(USER, PASSWD, HOST, WSDL_FOLDER, SERVICES) | ||||||
|  | h1util.download_wsdls() | ||||||
|  |  | ||||||
|  | # Preparing proxies | ||||||
|  | cos_svc = h1util.get_proxy("CourseOfStudyService") | ||||||
|  | person_svc = h1util.get_proxy("PersonService") | ||||||
|  | person_address_svc = h1util.get_proxy("PersonAddressService") | ||||||
|  | student2_svc = h1util.get_proxy("StudentService201812") | ||||||
|  | student_svc = h1util.get_proxy("StudentService") | ||||||
|  | value_svc = h1util.get_proxy("KeyvalueService") | ||||||
|  |  | ||||||
|  | #help(person_svc.service.updatePerson) | ||||||
|  | Person = person_svc.get_type("ns0:PersonExisting") | ||||||
|  | PersonInfo = person_svc.get_type("ns0:PersoninfoDto") | ||||||
|  | StudyBeforeDTO = student_svc.get_type("ns0:StudyBeforeDto") | ||||||
|  | EntranceQualificationDto = student_svc.get_type("ns0:EntranceQualificationDto") | ||||||
|  | Examplan70 = student_svc.get_type("ns0:Examplan70") | ||||||
|  | ExamrelationDto = student_svc.get_type("ns0:ExamrelationDto") | ||||||
|  | Examimport70 = student_svc.get_type("ns0:Examimport70") | ||||||
|  | Person70 = student_svc.get_type("ns0:Person70") | ||||||
|  |  | ||||||
|  | COUNTRIES = value_svc.service.getAllExtended(valueClass="CountryValue", lang="de") | ||||||
|  | #print(COUNTRIES) | ||||||
|  | TERMTYPES = value_svc.service.getAllExtended(valueClass="TermTypeValue", lang="de") | ||||||
|  | print(TERMTYPES) | ||||||
|  |  | ||||||
|  | TERM_WS = [t for t in TERMTYPES if t["uniquename"] == "WiSe"][0] | ||||||
|  | TERM_SS = [t for t in TERMTYPES if t["uniquename"] == "SoSe"][0] | ||||||
|  |  | ||||||
|  | def get_country_id_by_iso2(isocode): | ||||||
|  |     now = datetime.date(datetime.now()) | ||||||
|  |     result = [ | ||||||
|  |         c["id"] | ||||||
|  |         for c in COUNTRIES | ||||||
|  |         if c["iso3166_1_alpha_2"] == isocode | ||||||
|  |         and (c["validFrom"] < now and now < c["validTo"]) | ||||||
|  |     ] | ||||||
|  |     if len(result) == 1: | ||||||
|  |         return result[0] | ||||||
|  |     else: | ||||||
|  |         raise RuntimeError(f"The given isocode {isocode} could not be resolved exactly") | ||||||
|  |  | ||||||
|  | # Start of example: importing incoming students to hisinone stu | ||||||
|  |  | ||||||
|  | sample_student = { | ||||||
|  |     "course_of_study_uniquename": "97|271|-|-|H|-|-|P|-|9|", | ||||||
|  |     "surname": "Mustermann", | ||||||
|  |     "firstname": "Max", | ||||||
|  |     "private_email": "max.mustermann@kdv.bayern", | ||||||
|  |     "gender": "M", # one of D, M, U, W (see KeyvalueService with valueClass=GenderValue)     | ||||||
|  |     "home_post_address": { | ||||||
|  |         "street": "Rainerstraße 28", | ||||||
|  |         "postcode": "5020", | ||||||
|  |         "city": "Salzburg", | ||||||
|  |         "country": "A", # At that Point its country.uniquename from hisinone  | ||||||
|  |                         #-> using the Mapping in COUNTRIES that can be resolved from iso too (its your decision what to use) | ||||||
|  |         "addresstag": "home" # not mandatory, but could be set | ||||||
|  |     },     | ||||||
|  |     "birthdate": "2000-02-01", | ||||||
|  |     "birthcity": "Dornbirn", | ||||||
|  |     "country": "AT", # Here we use the ISO 3166.1 Alpha 2 Code | ||||||
|  |     "nationality_country": "AT", # Here we use the ISO 3166.1 Alpha 2 Code     | ||||||
|  |     "home_university_first_term_year": 2021, | ||||||
|  |     "home_university_country_iso": "CZ", | ||||||
|  |     "entrance_qualification_country_iso": "CZ", | ||||||
|  |     "entrance_qualification_grade": 1.3, | ||||||
|  |     "entrance_qualification_date": "12.12.2020", | ||||||
|  |     "entrance_qualification_year": "2020" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # 1. Fetching the course information from HISinOne | ||||||
|  | tmp_courses = cos_svc.service.findCourseOfStudy201812(uniquename=sample_student["course_of_study_uniquename"]) | ||||||
|  | if(len(tmp_courses) != 1): | ||||||
|  |     raise Exception("Invalid course_of_study given") | ||||||
|  |  | ||||||
|  | course_of_study = tmp_courses[0] | ||||||
|  |  | ||||||
|  | #print(course_of_study) | ||||||
|  |  | ||||||
|  | # 2. Creating a preliminary student object in HISinOne | ||||||
|  | student_id = student2_svc.service.createCandidateStudent202012( | ||||||
|  |     surname=sample_student["surname"], | ||||||
|  |     firstname=sample_student["firstname"], | ||||||
|  |     gender=sample_student["gender"], | ||||||
|  |     courseOfStudyIds=[ | ||||||
|  |         course_of_study["courseofstudyId"] | ||||||
|  |     ], | ||||||
|  |     generateRegnumber=True, | ||||||
|  |     studentstatus="H", # To be checked   | ||||||
|  |     studystatus="N", # to be confirmed by german moveon usergroup, could be E as well but maybe will be constant for all exchangestudents | ||||||
|  |     addresstag="home", # see KeyvalueService with valueClass = 'AddresstagValue' | ||||||
|  |  | ||||||
|  |     # Attention, addresses outside of germany at the are producing an error at the moment | ||||||
|  |     # this is a bug in hisinone which will be solved in next version of HISinOne:  | ||||||
|  |     # | ||||||
|  |     # KDV internal tickt: 4538,  | ||||||
|  |     # Ticket at HIS https://hiszilla.his.de/hiszilla/show_bug.cgi?id=291198 | ||||||
|  |     #  | ||||||
|  |     # Workaround is not to use this attribute | ||||||
|  |     #postaddress=sample_student["home_post_address"] | ||||||
|  |     # and do 2.2. instead | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | print(student_id) | ||||||
|  |  | ||||||
|  | # 2.1. fetching missing IDs | ||||||
|  | student_detail = student2_svc.service.readStudentByStudentId(studentId=student_id) | ||||||
|  |  | ||||||
|  | person_id = student_detail["personId"] | ||||||
|  | registrationnumber = student_detail["registrationnumber"] | ||||||
|  | print(f"person_id={person_id}, registrationnumber={registrationnumber}") | ||||||
|  |  | ||||||
|  | # 2.2. Adding post address within a separate call: (Workaround from https://hiszilla.his.de/hiszilla/show_bug.cgi?id=291198) | ||||||
|  | address_id = person_address_svc.service.createPostaddress( | ||||||
|  |     personId=person_id, | ||||||
|  |     notificationCategory="STU", # Use STU for primary and STUALL for all additional ones in case of incomings | ||||||
|  |     postaddress=sample_student["home_post_address"] | ||||||
|  | ) | ||||||
|  | print(f"AddressID: {address_id}") | ||||||
|  |  | ||||||
|  | # 2.3. Adding Information about date and place of birth, nationality and so on | ||||||
|  | # PersonService.readPerson201912 -> https://hisinone-7350-s.kdv-fh-bayern.de/qisserver/services2/PersonService?wsdl#op.id28 | ||||||
|  | # PersonService.savePerson -> https://hisinone-7350-s.kdv-fh-bayern.de/qisserver/services2/PersonService?wsdl#op.id33 | ||||||
|  | person = person_svc.service.readPerson(id=person_id) | ||||||
|  | print(person) | ||||||
|  |  | ||||||
|  | person.allfirstnames=person.firstname | ||||||
|  | #person.academicdegree=... if needed | ||||||
|  | person.dateofbirth=sample_student["birthdate"] | ||||||
|  | person.gender=sample_student["gender"] | ||||||
|  | person.birthcity=sample_student["birthcity"] | ||||||
|  | person.country=sample_student["country"] | ||||||
|  |  | ||||||
|  | if person.personinfo is None: | ||||||
|  |     pinfo = PersonInfo(familyStatusId=1, hasDoneService=False, nationalityId=get_country_id_by_iso2(sample_student["nationality_country"])) | ||||||
|  |     #pinfo.nationality=staat | ||||||
|  |     person.personinfo = pinfo | ||||||
|  | else: | ||||||
|  |     #person.personinfo.nationality=staat | ||||||
|  |     person.personinfo.familyStatusId=1 | ||||||
|  |     person.personinfo.hasDoneService=False | ||||||
|  |     person.personinfo.nationalityId=get_country_id_by_iso2(sample_student["nationality_country"])         | ||||||
|  |  | ||||||
|  | person_svc.service.updatePerson(person) | ||||||
|  |  | ||||||
|  | # 2.4. Adding private email address | ||||||
|  | eaddress_id = person_address_svc.service.createEmail( | ||||||
|  |     personId=person_id,  | ||||||
|  |     notificationCategory="STUALL",  | ||||||
|  |     email={ | ||||||
|  |         "emailValue": sample_student["private_email"], | ||||||
|  |         "eaddresstype": "email", | ||||||
|  |         "addresstag": "privat" | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | print(eaddress_id) | ||||||
|  |  | ||||||
|  | # 2.5. Add information about the university (just country) the exchange student ist coming from | ||||||
|  | #      for more options see definition at https://hisinone-7350-s.kdv-fh-bayern.de/qisserver/services2/StudentService?wsdl#op.id20 | ||||||
|  | study_before = StudyBeforeDTO( | ||||||
|  |     firstTermYear=datetime.now().year, | ||||||
|  |     firstTermTermTypeValueId=TERM_WS["id"], # Set it by real term type | ||||||
|  |     ownuniversityTermYear=sample_student["home_university_first_term_year"], | ||||||
|  |     countryId=get_country_id_by_iso2(sample_student["home_university_country_iso"]) | ||||||
|  | ) | ||||||
|  | student_svc.service.saveStudyBeforeForPerson(studyBefore=study_before, personId=person_id) | ||||||
|  |  | ||||||
|  | # 2.6. adding some entrance qualification information | ||||||
|  | #      (in Germany its called "Hochschulzugangsberechtigung" or "HZB") | ||||||
|  | ENTRANCE_QUALIFICATION_TYPES = value_svc.service.getAllExtended(valueClass="EntranceQualificationTypeValue", lang="de") | ||||||
|  | #print(ENTRANCE_QUALIFICATION_TYPES) | ||||||
|  | eq_foreign_country = [ | ||||||
|  |     eq  | ||||||
|  |     for eq in ENTRANCE_QUALIFICATION_TYPES | ||||||
|  |     if eq["astat"] == '79' # use 79 if there is no information about this in MoveOn, if there is some, use correct information | ||||||
|  | ][0] | ||||||
|  |  | ||||||
|  | exam_import = Examimport70( | ||||||
|  |     countryId=get_country_id_by_iso2(sample_student["entrance_qualification_country_iso"]), | ||||||
|  |     foreignGrade=sample_student["entrance_qualification_grade"] | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | examrelation = ExamrelationDto(workstatusId=1) | ||||||
|  | examplan = Examplan70( | ||||||
|  |     dateOfWork=sample_student["entrance_qualification_date"], | ||||||
|  |     year=sample_student["entrance_qualification_year"], | ||||||
|  |     personId=person_id, | ||||||
|  |     unitId=1, # Can be used als constant for entrance_qualifications | ||||||
|  |     defaultExamrelation=examrelation, | ||||||
|  |     examimport=exam_import | ||||||
|  | ) | ||||||
|  | entrance_qualification = EntranceQualificationDto( | ||||||
|  |     entranceQualificationTypeId=eq_foreign_country["id"], | ||||||
|  |     examplan=examplan | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | # Webservicerole needs additional right cm.app.entrancequalification.EDIT_ENTRANCEQUALIFICATION to perform this operation | ||||||
|  | student_svc.service.saveHZB(eq=entrance_qualification, ausinland=1) | ||||||
							
								
								
									
										106
									
								
								outgoings_from_stu.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								outgoings_from_stu.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | |||||||
|  | import re | ||||||
|  |  | ||||||
|  | from datetime import datetime | ||||||
|  | from h1wsutils import H1WebServiceUtils | ||||||
|  |  | ||||||
|  | # Some configuration Data statically added (for examples only!) | ||||||
|  | USER        = "mo_webservice_user" | ||||||
|  | PASSWD      = "geheim" | ||||||
|  | HOST        = "hisinone-7350-s" | ||||||
|  | WSDL_FOLDER = "wsdl" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SERVICES = ( | ||||||
|  |     "StayAbroadService", | ||||||
|  |     "PersonService",  | ||||||
|  |     "PersonAddressService",    | ||||||
|  |     "StudentService201812", | ||||||
|  |     "StudentService", | ||||||
|  |     "KeyvalueService" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | h1util = H1WebServiceUtils(USER, PASSWD, HOST, WSDL_FOLDER, SERVICES) | ||||||
|  | h1util.download_wsdls() | ||||||
|  |  | ||||||
|  | # Preparing proxies | ||||||
|  | abroad_svc = h1util.get_proxy("StayAbroadService") | ||||||
|  | person_svc = h1util.get_proxy("PersonService") | ||||||
|  | person_address_svc = h1util.get_proxy("PersonAddressService") | ||||||
|  | student2_svc = h1util.get_proxy("StudentService201812") | ||||||
|  | student_svc = h1util.get_proxy("StudentService") | ||||||
|  | value_svc = h1util.get_proxy("KeyvalueService") | ||||||
|  |  | ||||||
|  | # Input data for example, has to be replaced with values from real system | ||||||
|  | # in move on environment | ||||||
|  | #USERNAME_FROM_SHIBBOLETH = "albrecht4@beispielhochschule.de" | ||||||
|  | #FOREIGN_COUNTRY_ISO = "AU" # iso3166_1_alpha_2 | ||||||
|  |  | ||||||
|  | # Alternative ones for testing | ||||||
|  | USERNAME_FROM_SHIBBOLETH = "bauer2@beispielhochschule.de" | ||||||
|  | FOREIGN_COUNTRY_ISO = "DK" # iso3166_1_alpha_2 | ||||||
|  |  | ||||||
|  | # Some simple sample for validating and handling the fully qualified username from Shibboleth | ||||||
|  | UNIVERSITY_SUFFIX_SHIBBOLETH_REGEX = "^(?P<username>[a-zA-Z0-9]+)@beispielhochschule.de$" | ||||||
|  |  | ||||||
|  | matches = re.match(UNIVERSITY_SUFFIX_SHIBBOLETH_REGEX, USERNAME_FROM_SHIBBOLETH) | ||||||
|  | if not matches: | ||||||
|  |     print("Invalid User, not allowed to be used in this context") | ||||||
|  |     exit(code=1) | ||||||
|  |  | ||||||
|  | username = matches["username"] | ||||||
|  |  | ||||||
|  | # Finding person by username | ||||||
|  | person_ids = person_svc.service.findPerson( | ||||||
|  |     username=username,  | ||||||
|  |     studyTermYear=datetime.now().year # To focus the problem that usernames can be reused for new persons after some time of inactivity | ||||||
|  | ) | ||||||
|  | if len(person_ids) != 1: | ||||||
|  |     print(f"ERROR: user assignment invalid or not existent, please check it in HISinOne ({len(person_ids)})") | ||||||
|  |     exit(code=2) | ||||||
|  |  | ||||||
|  | person_id = person_ids[0] | ||||||
|  |  | ||||||
|  | # Fetching information about the user | ||||||
|  | student_info = student2_svc.service.readStudentByPersonId( | ||||||
|  |     person_id,  | ||||||
|  |     withDegreePrograms=True, | ||||||
|  |     withAddresses=True     | ||||||
|  | ) | ||||||
|  | print(student_info) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # Then continue to work in MoveOn | ||||||
|  | # | ||||||
|  | # | ||||||
|  |  | ||||||
|  | # After student is back from exchange semester, write back statistics data to HISinOne | ||||||
|  |  | ||||||
|  | # Those calls you can use to see what values are available within HISinOne | ||||||
|  | #STAY_ABROAD_TYPES = value_svc.service.getAll(valueClass="StayAbroadTypeValue", lang="de") | ||||||
|  | #print(STAY_ABROAD_TYPES) | ||||||
|  |  | ||||||
|  | #MOBILITY_PROGRAMS = value_svc.service.getAll(valueClass="MobilityProgramValue", lang="de") | ||||||
|  | #print(MOBILITY_PROGRAMS) | ||||||
|  |  | ||||||
|  | # In our sample case, the person did studies on a foreign university | ||||||
|  | STAY_ABROAD_TYPE = "01" | ||||||
|  | RESEARCH_FACILITY_TYPE="UNI" | ||||||
|  | # and he did this via ERASMUS which means an EU-Program | ||||||
|  | MOBILITY_PROGRAM = "01" | ||||||
|  |  | ||||||
|  | # Note: | ||||||
|  | # calling webservice user needs the right cs.psv.stayabroad.EDIT_STAYABROAD within hisinone! | ||||||
|  | result = abroad_svc.service.createStayAbroad( | ||||||
|  |     personId=person_id, | ||||||
|  |     country=FOREIGN_COUNTRY_ISO, # iso3166_1_alpha_2 of the country the student has been to | ||||||
|  |     numberOfMonth=7, | ||||||
|  |     startdate="2022-01-15", | ||||||
|  |     enddate="2022-07-15", | ||||||
|  |     stayAbroadTypeValue=STAY_ABROAD_TYPE, | ||||||
|  |     mobilityProgramValue=MOBILITY_PROGRAM, | ||||||
|  |     researchFacilityName="Sampleuniversity of Denmark", | ||||||
|  |     researchFacilityTypeValue=RESEARCH_FACILITY_TYPE | ||||||
|  | ) | ||||||
		Reference in New Issue
	
	Block a user
	 Wolfgang Wiedermann
					Wolfgang Wiedermann