/* imp-daily.p - Import daily attendance */ /* Fld 1 Bldg Code 2 Student ID 3 Atnd Date 4 Atnd Time (can be blank) 5 Atnd Code 6 Parent Contacted (blank if none, name if any) 7 Comments */ /* Include commons */ {common.i NEW} {p-init.i "'IMPORTER'"} {cldrutil.i DEFINE NEW} {atndutil.i DEFINE NEW} /* Constants */ &SCOPED WriteCmd PUT STREAM LogStream UNFORMATTED &SCOPED WriteHdr "#" LineCnt ", " ImportText[2] ", " ImportText[3] ": " &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 Done AS LOGICAL NO-UNDO. DEFINE VARIABLE TheTime AS CHARACTER NO-UNDO. DEFINE VARIABLE AtndDate AS DATE NO-UNDO. DEFINE VARIABLE itCounts AS LOGICAL NO-UNDO. /* Define Buffers */ DEFINE BUFFER YearBuff FOR school-year. DEFINE BUFFER BldgBuff FOR building. DEFINE BUFFER VrsnBuff FOR schd-version. DEFINE BUFFER AltAtnd FOR atnd-code. DEFINE BUFFER theGroup FOR atnd-calendar-group. /* 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) " Daily Attendance 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 attendance 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 Daily Attendance ". /* 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 attendance, please be patient...". FOR EACH stu-daily-atnd: DELETE stu-daily-atnd. END. HIDE MESSAGE NO-PAUSE. END. /* Load the profile */ FIND FIRST spm-prof NO-LOCK. /* 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] = ?) OR (ImportText[5] = "") OR (ImportText[5] = ?) 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 student is already on file */ FIND stu-base WHERE stu-base.stu-id = ImportText[2] NO-ERROR. IF AVAILABLE stu-base THEN FIND stu-year OF YearBuff WHERE stu-year.stu-seq = stu-base.stu-seq NO-ERROR. IF NOT AVAILABLE stu-base OR NOT AVAILABLE stu-year THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Student is not on file, NOT imported" SKIP. NEXT ImportLoop. END. /* Convert the attendance date */ AtndDate = DATE(ImportText[3]) NO-ERROR. IF ERROR-STATUS:ERROR THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Bad date for attendance entry, NOT imported" SKIP. NEXT ImportLoop. END. /* Load the day */ {atndutil.i SET CURRENT_BUILDING BldgBuff} {atndutil.i GET PRIMARY_GROUP theGroup} {atndutil.i IS MEMBERSHIP_DAY theGroup AtndDate itCounts} IF NOT itCounts THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Missing or non-membership day in primary atnd calendar, NOT imported" SKIP. NEXT ImportLoop. END. /* Load/create the attendance code */ FIND FIRST atnd-code OF BldgBuff NO-LOCK WHERE atnd-code.atnd-code-name = ImportText[5] NO-ERROR. IF NOT AVAILABLE atnd-code THEN DO: IF NOT AutoCreate THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Unknown atnd code " ImportText[5] ", NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. CREATE atnd-code. ASSIGN atnd-code.school-year-id = BldgBuff.school-year-id atnd-code.bldg-id = BldgBuff.bldg-id atnd-code.atnd-code-name = CAPS(ImportText[5]) atnd-code.description = "<< CREATED BY IMPORTER >>". {&WriteLog} "Created atnd code " ImportText[5] ", Please check it out" SKIP. END. {atndutil.i GET ATND_GROUP stu-year theGroup} {atndutil.i IS ATND_REPORT_DATE theGroup AtndDate itCounts} IF NOT itCounts THEN NEXT. /* See if there is already an entry for this date */ FIND FIRST stu-daily-atnd WHERE (stu-daily-atnd.school-year-id = BldgBuff.school-year-id) AND (stu-daily-atnd.bldg-id = BldgBuff.bldg-id) AND (stu-daily-atnd.current-entry = Yes) AND (stu-daily-atnd.stu-seq = stu-year.stu-seq) AND (stu-daily-atnd.atnd-date = AtndDate) NO-ERROR. IF AVAILABLE stu-daily-atnd THEN DO: /* Handle unreplacable mode */ IF NOT ReplaceMode THEN DO: {&WriteLog} "Existing atnd entry for this date, NOT imported" SKIP. NEXT ImportLoop. END. /* Load ancillary records */ FIND stu-contact OF stu-daily-atnd NO-LOCK NO-ERROR. FIND AltAtnd OF stu-daily-atnd NO-LOCK. /* Create a backup */ EXPORT STREAM ExportStream BldgBuff.bldg-code stu-year.stu-id stu-daily-atnd.atnd-date stu-daily-atnd.atnd-time AltAtnd.atnd-code-name (IF stu-daily-atnd.parent-contacted AND AVAILABLE stu-contact THEN stu-contact.contact-name ELSE "") stu-daily-atnd.comments. END. ELSE DO: /* Create an entry */ CREATE stu-daily-atnd. ASSIGN stu-daily-atnd.school-year-id = stu-year.school-year-id stu-daily-atnd.bldg-id = stu-year.bldg-id stu-daily-atnd.stu-seq = stu-year.stu-seq stu-daily-atnd.atnd-date = AtndDate. END. /* See if we have a contact for the student */ IF (ImportText[6] <> "") AND (ImportText[6] <> ?) THEN DO: FIND FIRST stu-contact NO-LOCK WHERE (stu-contact.stu-seq = stu-year.stu-seq) AND (stu-contact.contact-name BEGINS ImportText[6]) NO-ERROR. IF NOT AVAILABLE stu-contact THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Parental contact not on file for student, NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. ImportText[6] = stu-contact.contact-name. END. /* Verify the time */ RUN vrfytime.p (ImportText[4], OUTPUT TheTIme). IF TheTime = ? THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Bad time for atnd entry, NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. /* Do major assigns */ ASSIGN stu-daily-atnd.atnd-time = ImportText[4] stu-daily-atnd.atnd-code-id = atnd-code.atnd-code-id stu-daily-atnd.comments = ImportText[7] NO-ERROR. /* Check for errors */ IF ERROR-STATUS:ERROR THEN DO: ErrorCnt = ErrorCnt + 1. {&WriteLog} "Errors importing/converting data, NOT imported" SKIP. UNDO ImportLoop, NEXT ImportLoop. END. /* Handle a parent contact */ IF ImportText[6] <> "" AND (ImportText[6] <> ?) THEN ASSIGN stu-daily-atnd.parent-contacted = Yes stu-daily-atnd.stu-contact-seq = stu-contact.stu-contact-seq stu-daily-atnd.parent-contacted-date = stu-daily-atnd.atnd-date stu-daily-atnd.parent-contacted-at = stu-daily-atnd.atnd-time. ELSE ASSIGN stu-daily-atnd.parent-contacted = No stu-daily-atnd.stu-contact-seq = ? stu-daily-atnd.parent-contacted-date = ? stu-daily-atnd.parent-contacted-at = "". 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 */ {atndutil.i CLEAN_UP} {safe-msg.i "'Import Complete'"} RETURN.