/* imp-crscat.p - Import the course catalog */ /* Format for import lines is 1 - BldgCode 2 - Course Code 3 - Course Description 4 - Credits 5 - Department (blank = MISCDEPT) 6 - Course Group (blank = MISC-GRP) 7 - Course Fee 8 - Grading policy (Letter, Pass/Fail, Numeric. Blank=Letter) 9 - Seat limit (? = No limit, <> ? is seat limit) 10 - FTE Limit (? = No limit, <> ? is FTE limit) 11 - Course grading level (blank=REGULAR) 12 - Course Priority (blank=building default) 13 - Allow Conflicts? Y/N 14 - Blocked course (blank, MASTER or Course this is blocked to) 15 - Include in attendance? Y/N 16 - Include in conflict reports? Y/N 17 - Include in GPA calcs? Y/N 18 - Include in honor rolls? Y/N 19 - Include in Progress reports? Y/N 20 - Include in ranking? Y/N 21 - Include in report cards? Y/N 22 - Include in Request analysis? Y/N 23 - Retakes get credit? Y/N 24 - Comments 25 - GPA multiplier */ /* Include commons */ {common.i NEW} {p-init.i "'IMPORTER'"} /* Constants */ &SCOPED WriteCmd PUT STREAM LogStream UNFORMATTED &SCOPED WriteHdr "#" LineCnt ", " ImportText[1] ", " ImportText[2] ": " &SCOPED WriteLog {&WriteCmd} {&WriteHdr} /* Define Variables */ DEFINE VARIABLE SchoolYear AS CHARACTER NO-UNDO. DEFINE VARIABLE ImportFile AS CHARACTER NO-UNDO. DEFINE VARIABLE ExportFile AS CHARACTER NO-UNDO. DEFINE VARIABLE LogFile AS CHARACTER NO-UNDO. DEFINE VARIABLE ReplaceMode AS LOGICAL NO-UNDO. DEFINE VARIABLE PurgeMode AS LOGICAL NO-UNDO. DEFINE VARIABLE ImportText AS CHARACTER EXTENT 50 NO-UNDO. DEFINE VARIABLE LineCnt AS INTEGER NO-UNDO. DEFINE VARIABLE AutoCreate AS LOGICAL NO-UNDO. /* Variables for statistics */ DEFINE VARIABLE TotalLineCnt AS INTEGER NO-UNDO. DEFINE VARIABLE StartTime AS INTEGER NO-UNDO. DEFINE VARIABLE LastUpdate AS INTEGER NO-UNDO. DEFINE VARIABLE PercentDone AS DECIMAL NO-UNDO. DEFINE VARIABLE LinesPerSec AS DECIMAL NO-UNDO. DEFINE VARIABLE ErrorCnt AS INTEGER NO-UNDO. DEFINE VARIABLE Elapsed AS CHARACTER NO-UNDO. DEFINE VARIABLE TimeRemain AS CHARACTER NO-UNDO. DEFINE VARIABLE BlockMode AS CHARACTER NO-UNDO. DEFINE VARIABLE ThePtr AS INTEGER NO-UNDO. /* Define Buffers */ DEFINE BUFFER YearBuff FOR school-year. DEFINE BUFFER BldgBuff FOR building. DEFINE BUFFER VrsnBuff FOR schd-version. DEFINE BUFFER AltCourse FOR course-catalog. /* Define Streams */ DEFINE STREAM ImportStream. DEFINE STREAM LogStream. DEFINE STREAM ExportStream. /* Status frame */ FORM TotalLineCnt COLUMN-LABEL "Total!Lines" FORMAT "zzzzz9" LineCnt COLUMN-LABEL "Curnt!Line" FORMAT "zzzzz9" PercentDone COLUMN-LABEL "%age!Done" FORMAT "zz9.99%" LinesPerSec COLUMN-LABEL "Lines!/sec" FORMAT "zz9.99" ErrorCnt COLUMN-LABEL "Errors" FORMAT "zzzz9" Elapsed COLUMN-LABEL "Elapsed!Time" TimeRemain COLUMN-LABEL "Time!Remain" WITH FRAME StatusFrame 1 DOWN CENTERED ROW 9 OVERLAY COLOR VALUE(the-color.c-proc) TITLE COLOR VALUE(the-color.c-title) " Course Catalog Importation Statistics ". /* First, get the import file */ QueryBlock: DO WHILE TRUE ON ERROR UNDO, RETURN ON ENDKEY UNDO, RETURN: /* Define the form */ FORM SchoolYear LABEL " School Year to import to" FORMAT "x(9)" ImportFile LABEL " Import from" FORMAT "x(255)" VIEW-AS FILL-IN SIZE 32 BY 1 SPACE(1) PurgeMode LABEL " Purge course catalogs first" FORMAT "Yes/No" SKIP ReplaceMode LABEL " Existing records should be" FORMAT "Replaced/Kept" LogFile LABEL " Log import results to" FORMAT "x(255)" VIEW-AS FILL-IN SIZE 32 BY 1 SPACE(1) AutoCreate LABEL " Auto-create codes" FORMAT "Yes/No" SKIP ExportFile LABEL " Backup replaced data to" FORMAT "x(255)" VIEW-AS FILL-IN SIZE 32 BY 1 WITH FRAME QueryFrame OVERLAY 1 DOWN CENTERED ROW 10 SIDE-LABELS COLOR VALUE(the-color.c-proc) PROMPT VALUE(the-color.c-input). /* Default things for the user */ ON LEAVE OF ImportFile IN FRAME QueryFrame DO: /* Define Variables */ DEFINE VARIABLE DotPtr AS INTEGER NO-UNDO. /* Get pointer to decimal */ DotPtr = INDEX(ImportFile:SCREEN-VALUE, "."). IF DotPtr = 0 THEN RETURN. /* Default the log file */ IF LogFile:SCREEN-VALUE = "" THEN LogFile:SCREEN-VALUE = SUBSTR(SELF:SCREEN-VALUE, 1, DotPtr - 1) + ".log". /* Default the backup file */ IF ExportFile:SCREEN-VALUE = "" THEN ExportFile:SCREEN-VALUE = SUBSTR(SELF:SCREEN-VALUE, 1, DotPtr - 1) + ".org". END. /* Query the user */ UPDATE SchoolYear SKIP ImportFile SKIP PurgeMode SKIP ReplaceMode SKIP LogFile SKIP AutoCreate SKIP ExportFile SKIP WITH FRAME QueryFrame OVERLAY 1 DOWN CENTERED ROW 10 SIDE-LABELS COLOR VALUE(the-color.c-proc) PROMPT VALUE(the-color.c-input) TITLE COLOR VALUE(the-color.c-title) " Import Course Catalog ". /* See if the note exists */ IF SEARCH(ImportFile) = ? THEN DO: BELL. {safe-msg.i "'Cannot find the import source file'"} NEXT. END. /* Load the year buffer */ FIND YearBuff WHERE YearBuff.school-year-name = SchoolYear NO-LOCK NO-ERROR. IF NOT AVAILABLE YearBuff THEN DO: BELL. {safe-msg.i "'School year not on file'"} NEXT. END. /* Make sure the backup file should be overwritten */ IF SEARCH(ExportFile) <> ? THEN DO: DO ON ERROR UNDO, NEXT QueryBlock ON ENDKEY UNDO, NEXT QueryBlock: MESSAGE COLOR VALUE(the-color.c-alert) " " ExportFile "already exists " SKIP " Do you want to overwrite it?" SKIP VIEW-AS ALERT-BOX QUESTION BUTTONS YES-NO UPDATE OverwriteFile AS LOGICAL. END. /* Iterate if not okay */ IF NOT OverwriteFile THEN NEXT. END. /* Done */ LEAVE. END. /* Purge catalogs */ IF PurgeMode THEN DO: MESSAGE "Purging course catalogs, please be patient...". FOR EACH course-catalog OF YearBuff: DELETE course-catalog. END. FOR EACH course-stats OF YearBuff: DELETE course-stats. END. FOR EACH course-block OF YearBuff: DELETE course-block. END. HIDE MESSAGE NO-PAUSE. END. /* Get line count */ INPUT STREAM ImportStream THROUGH VALUE("wc -l " + ImportFile). IMPORT STREAM ImportStream ImportText. INPUT STREAM ImportStream CLOSE. TotalLineCnt = INTEGER(ImportText[1]). DISPLAY TotalLineCnt WITH FRAME StatusFrame. /* Open the file */ INPUT STREAM ImportStream FROM VALUE(ImportFile). OUTPUT STREAM LogStream TO VALUE(LogFile) PAGE-SIZE 0. OUTPUT STREAM ExportStream TO VALUE(ExportFile) PAGE-SIZE 0. /* Hide the query frame */ HIDE FRAME QueryFrame NO-PAUSE. /* Reset counters */ ASSIGN StartTime = TIME LastUpdate = StartTime. /* Begin Processing */ ImportLoop: REPEAT ON ERROR UNDO, LEAVE ON ENDKEY UNDO, LEAVE: /* Get a line */ ImportText = "". IMPORT STREAM ImportStream ImportText. LineCnt = LineCnt + 1. /* Update status display */ IF (TIME - LastUpdate) > 2 THEN DO: DISPLAY LineCnt (LineCnt / TotalLineCnt) * 100 @ PercentDone LineCnt / (TIME - StartTime) @ LinesPerSec ErrorCnt STRING(TIME - StartTime, "HH:MM:SS") @ Elapsed STRING(INTEGER((TotalLineCnt - LineCnt) / (LineCnt / (TIME - StartTime))), "HH:MM:SS") @ TimeRemain WITH FRAME StatusFrame. LastUpdate = TIME. END. /* Make sure we have our required fields */ IF (ImportText[1] = "") OR (ImportText[1] = ?) OR (ImportText[2] = "") OR (ImportText[2] = ?) OR (ImportText[3] = "") OR (ImportText[3] = ?) THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "One or more REQUIRED fields missing, NOT imported" SKIP. NEXT ImportLoop. END. /* Make sure we can find the building */ FIND FIRST BldgBuff OF YearBuff NO-LOCK WHERE BldgBuff.bldg-code = ImportText[1] NO-ERROR. IF NOT AVAILABLE BldgBuff THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Bldg is not on file, NOT imported" SKIP. NEXT ImportLoop. END. /* Load the version buffer */ FIND FIRST VrsnBuff OF BldgBuff NO-LOCK WHERE VrsnBuff.active-schedule = Yes. /* See if the course is already on file */ FIND FIRST course-catalog OF BldgBuff WHERE course-catalog.course-code = ImportText[2] NO-ERROR. IF AVAILABLE course-catalog THEN DO: /* Handle unreplacable mode */ IF NOT ReplaceMode THEN DO: {&WriteLog} "Existing course catalog on file, NOT imported" SKIP. NEXT ImportLoop. END. /* Load ancillary records */ FIND course-group OF course-catalog NO-LOCK. FIND department OF course-catalog NO-LOCK. FIND course-level OF course-catalog NO-LOCK. /* Handle course blocking */ IF course-catalog.course-blocks-by <> "None" THEN BlockMode = "MASTER". ELSE DO: FIND FIRST course-block OF VrsnBuff NO-LOCK WHERE course-block.block-course-id = course-catalog.course-id NO-ERROR. IF AVAILABLE course-block THEN DO: FIND AltCourse OF course-block NO-LOCK. BlockMode = AltCourse.course-code. END. ELSE BlockMode = "". END. /* Create a backup */ EXPORT STREAM ExportStream BldgBuff.bldg-code course-catalog.course-code course-catalog.description course-catalog.credits department.dept-name course-group.course-group-code course-catalog.course-fee course-catalog.grading-policy (IF course-catalog.enforce-seat-limit THEN course-catalog.max-seat-cnt ELSE ?) (IF course-catalog.enforce-fte-limit THEN course-catalog.max-fte ELSE ?) course-level.course-level-code course-catalog.course-priority course-catalog.allow-conflicts BlockMode course-catalog.include-attend course-catalog.include-conflict course-catalog.include-gpa course-catalog.include-honor course-catalog.include-progress course-catalog.include-rank course-catalog.include-report-card course-catalog.include-simple-tally course-catalog.retake-credit course-catalog.comments. END. ELSE DO: CREATE course-catalog. ASSIGN course-catalog.school-year-id = BldgBuff.school-year-id course-catalog.bldg-id = BldgBuff.bldg-id course-catalog.course-code = CAPS(ImportText[2]). END. /* Handle defaults */ IF (ImportText[5] = ?) OR (ImportText[5] = "") THEN ImportText[5] = "MISCDEPT". IF (ImportText[6] = ?) OR (ImportText[6] = "") THEN ImportText[6] = "MISC-GRP". IF (ImportText[8] = ?) OR (ImportText[8] = "") THEN ImportText[8] = "Letter". IF (ImportText[11] = ?) OR (ImportText[11] = "") THEN ImportText[11] = "REGULAR". IF (ImportText[25] = ?) OR (ImportText[25] = "") THEN ImportText[25] = "1". /* Lookup the department */ FIND FIRST department OF BldgBuff NO-LOCK WHERE department.dept-name = ImportText[5] NO-ERROR. IF NOT AVAILABLE department THEN DO: IF NOT AutoCreate THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Unknown department code " ImportText[5] ", course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. CREATE department. ASSIGN department.school-year-id = BldgBuff.school-year-id department.bldg-id = BldgBuff.bldg-id department.dept-name = CAPS(ImportText[5]) department.description = "<< CREATED BY IMPORTER >>". {&WriteLog} "Created department " ImportText[5] ", Please check it out" SKIP. END. /* Lookup the course group */ FIND FIRST course-group OF BldgBuff NO-LOCK WHERE course-group.course-group-code = ImportText[6] NO-ERROR. IF NOT AVAILABLE course-group THEN DO: IF NOT AutoCreate THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Unknown course group " ImportText[6] ", course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. /* Create a course group */ CREATE course-group. ASSIGN course-group.school-year-id = BldgBuff.school-year-id course-group.bldg-id = BldgBuff.bldg-id course-group.course-group-code = CAPS(ImportText[6]) course-group.description = "<< CREATED BY IMPORTER >>". {&WriteLog} "Created course group " ImportText[6] ", Please check it out" SKIP. END. /* Lookup the grading level */ FIND FIRST course-level OF BldgBuff NO-LOCK WHERE course-level.course-level-code = ImportText[11] NO-ERROR. IF NOT AVAILABLE course-level THEN DO: IF NOT AutoCreate THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Unknown course level " ImportText[11] ", course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. CREATE course-level. ASSIGN course-level.school-year-id = BldgBuff.school-year-id course-level.bldg-id = BldgBuff.bldg-id course-level.course-level-code = CAPS(ImportText[11]) course-level.description = "<< CREATED BY IMPORTER >>". {&WriteLog} "Created course level " ImportText[11] ", Please check it out" SKIP. END. /* Handle default priority */ IF (ImportText[12] = ?) OR (ImportText[12] = "") THEN DO: /* Determine the default priority for the building */ DO ThePtr = 1 TO EXTENT(BldgBuff.request-priority): IF BldgBuff.request-default[ThePtr] THEN DO: ImportText[12] = BldgBuff.request-priority[ThePtr]. LEAVE. END. END. END. /* Verify the priority */ DO ThePtr = 1 TO EXTENT(BldgBuff.request-priority): IF BldgBuff.request-priority[ThePtr] = ImportText[12] THEN DO: ImportText[12] = BldgBuff.request-priority[ThePtr]. LEAVE. END. END. IF ThePtr > EXTENT(BldgBuff.request-priority) THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Unknown course priority " ImportText[12] ", Course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. /* Verify the grading policy */ ThePtr = LOOKUP(ImportText[8], "Letter,Pass/Fail,Numeric"). IF ThePtr = 0 THEN DO: {&WriteLog} "Unknown grading policy " ImportText[8] ", course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. ImportText[8] = ENTRY(ThePtr, "Letter,Pass/Fail,Numeric"). /* Set blocking mode */ IF (ImportText[14] = "") OR (ImportText[14] = ?) THEN BlockMode = "None". ELSE IF ImportText[14] = "Master" THEN DO: /* Make sure we aren't part of an existing block */ FIND FIRST course-block OF VrsnBuff NO-LOCK WHERE course-block.block-course-id = course-catalog.course-id NO-ERROR. IF AVAILABLE course-block THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "This course is marked as blocked, but is already part of " "another blocked course, course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. /* Flag as a block master */ BlockMode = "All". END. ELSE DO: /* Make sure the master course exists */ FIND FIRST AltCourse OF BldgBuff NO-LOCK WHERE AltCourse.course-code = ImportText[14] NO-ERROR. IF NOT AVAILABLE AltCourse THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Master course " ImportText[14] " for blocked course not on file, course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. /* Make sure the master is in fact a blocked course */ IF AltCourse.course-blocks-by = "None" THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Master course " ImportText[14] " is not a blocked course, course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. /* Non-blocking course */ BlockMode = "None". END. /* Set things in place */ ASSIGN course-catalog.description = ImportText[3] course-catalog.credits = DECIMAL(ImportText[4]) course-catalog.dept-id = department.dept-id course-catalog.course-group-id = course-group.course-group-id course-catalog.course-fee = DECIMAL(ImportText[7]) course-catalog.grading-policy = ImportText[8] course-catalog.enforce-seat-limit = ImportText[9] <> ? course-catalog.max-seat-cnt = (IF ImportText[9] <> ? THEN INTEGER(ImportText[9]) ELSE course-catalog.max-seat-cnt) course-catalog.enforce-fte-limit = ImportText[10] <> ? course-catalog.max-fte = (IF ImportText[10] <> ? THEN INTEGER(ImportText[10]) ELSE course-catalog.max-fte) course-catalog.course-level-id = course-level.course-level-id course-catalog.course-priority = ImportText[12] course-catalog.allow-conflicts = ImportText[13] BEGINS "Y" course-catalog.course-blocks-by = BlockMode course-catalog.include-attend = ImportText[15] BEGINS "Y" course-catalog.include-conflict = ImportText[16] BEGINS "Y" course-catalog.include-gpa = ImportText[17] BEGINS "Y" course-catalog.include-honor = ImportText[18] BEGINS "Y" course-catalog.include-progress = ImportText[19] BEGINS "Y" course-catalog.include-rank = ImportText[20] BEGINS "Y" course-catalog.include-report-card = ImportText[21] BEGINS "Y" course-catalog.include-simple-tally = ImportText[22] BEGINS "Y" course-catalog.retake-credit = ImportText[23] BEGINS "Y" course-catalog.comments = ImportText[24] course-catalog.gpa-multiplier = DECIMAL(ImportText[25]). /* Check for errors */ IF ERROR-STATUS:ERROR THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Errors importing/converting course data, course NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. /* Create the course blocking */ IF (ImportText[14] <> ?) AND (ImportText[14] <> "") AND (ImportText[14] <> "Master") THEN DO: /* Load the master course */ FIND FIRST AltCourse OF BldgBuff NO-LOCK WHERE AltCourse.course-code = ImportText[14] NO-ERROR. /* See if we are already part of the block */ FIND FIRST course-block OF VrsnBuff NO-LOCK WHERE course-block.block-course-id = course-catalog.course-id NO-ERROR. IF NOT AVAILABLE course-block THEN DO: /* Find last block (if any) */ FIND LAST course-block OF VrsnBuff NO-LOCK WHERE course-block.course-id = AltCourse.course-id USE-INDEX course-block-num NO-ERROR. IF AVAILABLE course-block THEN ThePtr = course-block.block-num + 1. ELSE ThePtr = 1. /* Create a new block */ CREATE course-block. ASSIGN course-block.school-year-id = VrsnBuff.school-year-id course-block.bldg-id = VrsnBuff.bldg-id course-block.schd-version-id = VrsnBuff.schd-version-id course-block.course-id = AltCourse.course-id course-block.block-course-id = course-catalog.course-id course-block.course-required = Yes course-block.block-num = ThePtr. END. END. /* Make sure there is a statistics record */ FIND course-stats OF course-catalog NO-LOCK NO-ERROR. IF NOT AVAILABLE course-stats THEN DO: CREATE course-stats. ASSIGN course-stats.school-year-id = course-catalog.school-year-id course-stats.bldg-id = course-catalog.bldg-id course-stats.course-id = course-catalog.course-id. END. END. /* Final statistics update */ DISPLAY LineCnt (LineCnt / TotalLineCnt) * 100 @ PercentDone LineCnt / (TIME - StartTime) @ LinesPerSec ErrorCnt STRING(TIME - StartTime, "HH:MM:SS") @ Elapsed STRING(INTEGER((TotalLineCnt - LineCnt) / (LineCnt / (TIME - StartTime))), "HH:MM:SS") @ TimeRemain WITH FRAME StatusFrame. /* Close the input & log streams */ INPUT STREAM ImportStream CLOSE. OUTPUT STREAM LogStream CLOSE. OUTPUT STREAM ExportStream CLOSE. /* We are done */ {safe-msg.i "'Import Complete'"} RETURN.