diff --git a/src/main/java/edu/ucdavis/dss/ipa/api/components/course/CourseViewController.java b/src/main/java/edu/ucdavis/dss/ipa/api/components/course/CourseViewController.java index ead53c890..7296d61dc 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/api/components/course/CourseViewController.java +++ b/src/main/java/edu/ucdavis/dss/ipa/api/components/course/CourseViewController.java @@ -34,6 +34,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.sql.Array; import java.sql.Time; import java.text.ParseException; import java.util.*; @@ -54,6 +55,7 @@ public class CourseViewController { @Inject TermService termService; @Inject TeachingAssignmentService teachingAssignmentService; @Inject InstructorService instructorService; + @Inject BudgetScenarioService budgetScenarioService; @Inject DataWarehouseRepository dwRepository; @Inject Authorizer authorizer; @@ -881,4 +883,87 @@ public View downloadExcel(@PathVariable long workgroupId, @PathVariable long yea return null; } } + + @RequestMapping(value = "/api/courseView/workgroups/{workgroupId}/years/{year}/courses/{courseId}/sectionGroups/{sectionGroupId}/convert/{sequencePattern}", method = RequestMethod.POST, produces="application/json") + @ResponseBody + public List convertCourseOffering(@PathVariable Long workgroupId, @PathVariable Long year, @PathVariable Long courseId, @PathVariable Long sectionGroupId, @PathVariable String sequencePattern, HttpServletResponse httpResponse) { + authorizer.hasWorkgroupRole(workgroupId, "academicPlanner"); + Schedule schedule = this.scheduleService.findByWorkgroupIdAndYear(workgroupId, year); + + Course existingCourse = courseService.getOneById(courseId); + + Course course = new Course(); + course.setSubjectCode(existingCourse.getSubjectCode()); + course.setCourseNumber(existingCourse.getCourseNumber()); + course.setSequencePattern(sequencePattern); + course.setTitle(existingCourse.getTitle()); + course.setEffectiveTermCode(existingCourse.getEffectiveTermCode()); + course.setSchedule(schedule); + course.setUnitsHigh(existingCourse.getUnitsHigh()); + course.setUnitsLow(existingCourse.getUnitsLow()); + + Course newCourse = courseService.findOrCreateByCourse(course); + + SectionGroup sectionGroup = sectionGroupService.getOneById(sectionGroupId); + + + for(BudgetScenario budgetScenario : budgetScenarioService.findbyWorkgroupIdAndYear(workgroupId, year) ){ + // Do not update budget requests + if(!budgetScenario.getIsBudgetRequest()){ + SectionGroupCost existingSectionGroupCost = sectionGroupCostService.findBySubjectCodeAndCourseNumberAndSequencePatternAndBudgetScenarioIdAndTermCode( + existingCourse.getSubjectCode(), + existingCourse.getCourseNumber(), + sectionGroup.getCourse().getSequencePattern(), + budgetScenario.getId(), + sectionGroup.getTermCode() + ); + if(existingSectionGroupCost != null){ + SectionGroupCost conflictingSectionGroupCost = sectionGroupCostService.findBySubjectCodeAndCourseNumberAndSequencePatternAndBudgetScenarioIdAndTermCode( + existingCourse.getSubjectCode(), + existingCourse.getCourseNumber(), + sequencePattern, + budgetScenario.getId(), + sectionGroup.getTermCode() + ); + if(conflictingSectionGroupCost == null){ + existingSectionGroupCost.setSequencePattern(sequencePattern); + existingSectionGroupCost.setDisabled(false); + sectionGroupCostService.update(existingSectionGroupCost); + } else if (conflictingSectionGroupCost.isDisabled()){ + sectionGroupCostService.delete(conflictingSectionGroupCost.getId()); + existingSectionGroupCost.setSequencePattern(sequencePattern); + sectionGroupCostService.update(existingSectionGroupCost); + } + } + } + } + + Long seatCount = new Long(0); + for(Section oldSection : sectionGroup.getSections()){ + seatCount += oldSection.getSeats(); + sectionService.deleteWithCascade(oldSection); + } + + + sectionGroup.setCourse(newCourse); + sectionGroup.setPlannedSeats(seatCount.intValue()); + SectionGroup newSectionGroup = sectionGroupService.save(sectionGroup); + + Section section = new Section(); + if(sequencePattern.length() > 1){ + section.setSequenceNumber(sequencePattern); + } else { + section.setSequenceNumber(sequencePattern+"01"); + } + section.setSeats(seatCount); + section.setSectionGroup(sectionGroup); + sectionService.save(section); + + if (newCourse != null) { + return Arrays.asList(newCourse, newSectionGroup); + } else { + httpResponse.setStatus(HttpStatus.BAD_REQUEST.value()); + return null; + } + } } diff --git a/src/main/java/edu/ucdavis/dss/ipa/repositories/ActivityRepository.java b/src/main/java/edu/ucdavis/dss/ipa/repositories/ActivityRepository.java index b16957b19..323a72819 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/repositories/ActivityRepository.java +++ b/src/main/java/edu/ucdavis/dss/ipa/repositories/ActivityRepository.java @@ -1,10 +1,12 @@ package edu.ucdavis.dss.ipa.repositories; import edu.ucdavis.dss.ipa.entities.Activity; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; +import javax.transaction.Transactional; import java.util.List; public interface ActivityRepository extends CrudRepository { @@ -49,4 +51,9 @@ List findByWorkgroupIdAndYearAndTermCode( @Param("workgroupId") long workgroupId, @Param("year") long year, @Param("termCode") String termCode); + + @Modifying + @Transactional + @Query(value="delete from Activity a WHERE a.id = ?1") + void deleteById(long activityId); } diff --git a/src/main/java/edu/ucdavis/dss/ipa/repositories/SectionGroupCostRepository.java b/src/main/java/edu/ucdavis/dss/ipa/repositories/SectionGroupCostRepository.java index 1657a9729..f60a259c4 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/repositories/SectionGroupCostRepository.java +++ b/src/main/java/edu/ucdavis/dss/ipa/repositories/SectionGroupCostRepository.java @@ -28,4 +28,21 @@ public interface SectionGroupCostRepository extends CrudRepository findbyWorkgroupIdAndYear(@Param("workgroupId") long workgroupId, @Param("year") long year); SectionGroupCost findBySubjectCodeAndCourseNumberAndSequencePatternAndBudgetScenarioIdAndTermCode(String subjectCode, String courseNumber, String sequencePattern, long id, String termCode); + + @Query( " SELECT DISTINCT sgc" + + " FROM SectionGroupCost sgc, BudgetScenario bs, Budget b, Schedule s" + + " WHERE sgc.budgetScenario = bs" + + " AND bs.budget = b" + + " AND b.schedule = s" + + " AND s.workgroup.id = :workgroupId" + + " AND s.year = :year" + + " AND sgc.courseNumber = :courseNumber" + + " AND sgc.sequencePattern = :sequencePattern" + + " AND sgc.subjectCode = :subjectCode" ) + List findBySectionGroupDetails( + @Param("workgroupId") long workgroupId, + @Param("year") long year, + @Param("courseNumber") String courseNumber, + @Param("sequencePattern") String sequencePattern, + @Param("subjectCode") String subjectCode); } diff --git a/src/main/java/edu/ucdavis/dss/ipa/repositories/SectionRepository.java b/src/main/java/edu/ucdavis/dss/ipa/repositories/SectionRepository.java index 43e69f498..fbf087aac 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/repositories/SectionRepository.java +++ b/src/main/java/edu/ucdavis/dss/ipa/repositories/SectionRepository.java @@ -1,10 +1,12 @@ package edu.ucdavis.dss.ipa.repositories; import edu.ucdavis.dss.ipa.entities.Section; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; +import javax.transaction.Transactional; import java.util.List; public interface SectionRepository extends CrudRepository { @@ -53,4 +55,9 @@ Section findBySectionGroupIdAndSequenceNumber( List
findVisibleByWorkgroupIdAndYear( @Param("workgroupId") long workgroupId, @Param("year") long year); + + @Modifying + @Transactional + @Query(value="delete from Section s WHERE s.id = ?1") + void deleteById(long sectionId); } diff --git a/src/main/java/edu/ucdavis/dss/ipa/repositories/SyncActionRepository.java b/src/main/java/edu/ucdavis/dss/ipa/repositories/SyncActionRepository.java index b8531927f..e4688dcb4 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/repositories/SyncActionRepository.java +++ b/src/main/java/edu/ucdavis/dss/ipa/repositories/SyncActionRepository.java @@ -1,8 +1,15 @@ package edu.ucdavis.dss.ipa.repositories; import edu.ucdavis.dss.ipa.entities.SyncAction; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; -public interface SyncActionRepository extends CrudRepository { +import javax.transaction.Transactional; +public interface SyncActionRepository extends CrudRepository { + @Modifying + @Transactional + @Query(value="delete from SyncAction sa WHERE sa.id = ?1") + void deleteById(long syncActionId); } diff --git a/src/main/java/edu/ucdavis/dss/ipa/services/SectionGroupCostService.java b/src/main/java/edu/ucdavis/dss/ipa/services/SectionGroupCostService.java index 35cf95eac..e1bfcf6ed 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/services/SectionGroupCostService.java +++ b/src/main/java/edu/ucdavis/dss/ipa/services/SectionGroupCostService.java @@ -24,4 +24,6 @@ public interface SectionGroupCostService { void delete(Long sectionGroupCostId); SectionGroupCost updateFromSectionGroup(SectionGroup sectionGroup, BudgetScenario liveDataScenario); + + List findBySectionGroupDetails(long workgroupId, long year, String courseNumber, String sequencePattern, String subjectCode); } diff --git a/src/main/java/edu/ucdavis/dss/ipa/services/SectionService.java b/src/main/java/edu/ucdavis/dss/ipa/services/SectionService.java index 355eebff3..eeacdbed1 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/services/SectionService.java +++ b/src/main/java/edu/ucdavis/dss/ipa/services/SectionService.java @@ -27,4 +27,6 @@ public interface SectionService { List
findVisibleByWorkgroupIdAndYear(long workgroupId, long year); boolean hasValidSequenceNumber (Section section); + + void deleteWithCascade(Section section); } \ No newline at end of file diff --git a/src/main/java/edu/ucdavis/dss/ipa/services/jpa/JpaSectionGroupCostService.java b/src/main/java/edu/ucdavis/dss/ipa/services/jpa/JpaSectionGroupCostService.java index 8e8d65c89..7af7dacb4 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/services/jpa/JpaSectionGroupCostService.java +++ b/src/main/java/edu/ucdavis/dss/ipa/services/jpa/JpaSectionGroupCostService.java @@ -158,7 +158,9 @@ public SectionGroupCost update(SectionGroupCost sectionGroupCostDTO) { originalSectionGroupCost.setInstructor(instructorRepository.findById(sectionGroupCostDTO.getInstructorIdentification())); originalSectionGroupCost.setOriginalInstructor(instructorRepository.findById(sectionGroupCostDTO.getOriginalInstructorIdentification())); - originalSectionGroupCost.setInstructorType(instructorTypeRepository.findById(sectionGroupCostDTO.getInstructorType().getId())); + if(sectionGroupCostDTO.getInstructorType() != null){ + originalSectionGroupCost.setInstructorType(instructorTypeRepository.findById(sectionGroupCostDTO.getInstructorType().getId())); + } if(sectionGroupCostDTO.getReasonCategory() != null){ originalSectionGroupCost.setReasonCategory(reasonCategoryRepository.findById(sectionGroupCostDTO.getReasonCategory().getId())); } @@ -263,4 +265,16 @@ public SectionGroupCost updateFromSectionGroup(SectionGroup sectionGroup, Budget return sectionGroupCost; } + + @Override + public List findBySectionGroupDetails(long workgroupId, long year, String courseNumber, String sequencePattern, String subjectCode) { + return this.sectionGroupCostRepository.findBySectionGroupDetails( + workgroupId, + year, + courseNumber, + sequencePattern, + subjectCode + ); + } + } diff --git a/src/main/java/edu/ucdavis/dss/ipa/services/jpa/JpaSectionService.java b/src/main/java/edu/ucdavis/dss/ipa/services/jpa/JpaSectionService.java index 552c59aa9..7c5069ff2 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/services/jpa/JpaSectionService.java +++ b/src/main/java/edu/ucdavis/dss/ipa/services/jpa/JpaSectionService.java @@ -1,7 +1,9 @@ package edu.ucdavis.dss.ipa.services.jpa; import edu.ucdavis.dss.ipa.entities.*; +import edu.ucdavis.dss.ipa.repositories.ActivityRepository; import edu.ucdavis.dss.ipa.repositories.SectionRepository; +import edu.ucdavis.dss.ipa.repositories.SyncActionRepository; import edu.ucdavis.dss.ipa.services.*; import org.springframework.stereotype.Service; @@ -14,6 +16,8 @@ public class JpaSectionService implements SectionService { @Inject SectionRepository sectionRepository; + @Inject SyncActionRepository syncActionRepository; + @Inject ActivityRepository activityRepository; @Override public Section save(@Valid Section section) { @@ -42,7 +46,7 @@ public Section getOneById(Long id) { public Section updateSequenceNumber(Long sectionId, String newSequencePattern) { Section section = this.getOneById(sectionId); - if (newSequencePattern == null || newSequencePattern.length() == 0) { + if (newSequencePattern == null || newSequencePattern.length() == 0 || section == null) { return null; } @@ -114,4 +118,17 @@ public boolean hasValidSequenceNumber (Section section) { return true; } + + @Override + @Transactional + public void deleteWithCascade(Section section) { + for(SyncAction syncAction : section.getSyncActions()){ + sectionRepository.deleteById(syncAction.getId()); + } + for(Activity activity : section.getActivities()){ + System.err.println("Deleting activity " + activity.getId()); + activityRepository.deleteById(activity.getId()); + } + sectionRepository.deleteById(section.getId()); + } } diff --git a/src/main/java/edu/ucdavis/dss/ipa/utilities/ActivityLogFormatter.java b/src/main/java/edu/ucdavis/dss/ipa/utilities/ActivityLogFormatter.java index 6acb77247..88955cfde 100644 --- a/src/main/java/edu/ucdavis/dss/ipa/utilities/ActivityLogFormatter.java +++ b/src/main/java/edu/ucdavis/dss/ipa/utilities/ActivityLogFormatter.java @@ -17,6 +17,7 @@ public final class ActivityLogFormatter { // Fields to audit in course view for course HashMap courseViewCourse = new HashMap(); + courseViewCourse.put("sequencePattern", true); courseView.put("Course", courseViewCourse); // Fields to audit in course view for section @@ -30,8 +31,14 @@ public final class ActivityLogFormatter { courseViewSectionGroup.put("plannedSeats", true); courseViewSectionGroup.put("readerAppointments", true); courseViewSectionGroup.put("teachingAssistantAppointments", true); + courseViewSectionGroup.put("course", true); courseView.put("SectionGroup", courseViewSectionGroup); + // Fields to audit in course view for sectionGroupCost + HashMap courseViewSectionGroupCost = new HashMap(); + courseViewSectionGroupCost.put("sequencePattern", true); + courseView.put("SectionGroupCost", courseViewSectionGroupCost); + HashMap courseViewTeachingAssignment = new HashMap(); courseView.put("TeachingAssignment", courseViewTeachingAssignment); temp.put("courseViewController", courseView); @@ -273,6 +280,8 @@ public static String getFormattedModule(String moduleNameRaw, Object obj, String return "Support Staff Assignments"; } else if (obj instanceof Schedule && (propName.equals("supportStaffSupportCallReviewOpen") || propName.equals("instructorSupportCallReviewOpen"))) { return "Support Staff Assignments"; + } else if (obj instanceof SectionGroupCost && propName.equals("sequencePattern")){ + return "Budget"; } else { return ActivityLogFormatter.getFormattedModule(moduleNameRaw, obj); } @@ -685,6 +694,8 @@ public static String getFormattedPropName(String prop){ return "TAs"; case "supportStaffSupportCallReviewOpen": return "Student Review"; + case "sequencePattern": + return "Sequence Pattern"; default: return prop; } @@ -718,6 +729,9 @@ public static String getFormattedPropValue(String propName, Object obj){ } else if (obj instanceof ExpenseItemType) { ExpenseItemType expenseItemType = (ExpenseItemType) obj; return expenseItemType.getDescription(); + } else if (obj instanceof Course){ + Course course = (Course) obj; + return course.getSubjectCode() + " " + course.getCourseNumber() + " - " + course.getSequencePattern(); } else { if(obj != null){ return obj.toString(); @@ -756,6 +770,8 @@ public static Boolean isAudited(String module, String entity, String endpoint){ return true; } else if (entity.equals("TeachingAssignment") && endpoint.equals("courses" )){ return true; + } else if ((entity.equals("SectionGroup") || entity.equals("Course") || entity.equals("SectionGroupCost")) && endpoint.equals("convert")){ + return true; } else if (entity.endsWith("y") && (entity.toLowerCase().substring(0, entity.length() - 1) + "ies").equals(endpoint) ) { return true; }