** Get the raw data from the SQL server first and then post process it ** Get the rosters SQLEXEC(Applic.SQLHandle, "SELECT M.*, lst_procedure "+; "FROM t_mainroster M LEFT JOIN t_list ON rst_procedure = lst_itemid "+; "WHERE rst_startdate <=?(dDateTo+1) AND rst_enddate >= ?dDate","Mainroster") ConvertDatetimeToDate("MainRoster") ** Get blackout information SQLEXEC(Applic.SQLHandle, "SELECT * FROM t_Blackouts WHERE blk_StartDate <=?dDateto AND blk_EndDate >= ?dDate AND "+; "(blk_dr_id <> 0 OR blk_persfk <> 0)","Blk") ConvertDatetimeToDate("blk") ** now get all doctors and resources that are active in the given time period ** Yeah I know I can handle this bit TEXT .. ENDTEXT :) cString1 = "SELECT DISTINCT CONVERT(char(80),'[R] '+cnt_option) AS source, (apt_dr_id*2)+1 AS ID, apt_dr_id AS Rst_dr_id, "+; "CAST(0 AS Int) AS Rst_persfk, CAST(2 AS int) AS Rst_sort, cnt_Color "+; "FROM t_apptment "+; "INNER JOIN s_contents ON apt_dr_id = cnt_content_id AND cnt_title_id = 400 "+; "WHERE Apt_appdate BETWEEN ?dDate AND ?(dDateTo+1) AND apt_dr_id <> 0 "+; "UNION "+; "SELECT DISTINCT CONVERT(char(80),'[R] '+cnt_option) AS source, (rst_dr_id*2)+1 AS ID, Rst_dr_id, "+; "CAST(0 AS Int) AS Rst_persfk, CAST(2 AS int) AS Rst_sort, cnt_Color "+; "FROM t_mainroster "+; "INNER JOIN s_contents ON rst_dr_id = cnt_content_id AND cnt_title_id = 400 "+; "WHERE rst_startdate <=?(dDateTo+1) AND (rst_enddate >= ?dDate OR rst_enddate < '19100101')" cString2 = "SELECT DISTINCT CONVERT(char(80), RTRIM(prs_lastname)+', '+RTRIM(prs_firstname)+' '+prs_prefix) as Source, "+; "CONVERT(Int, rst_persfk*2) AS ID, CAST(0 AS Int) AS Rst_dr_id, Rst_persfk, CAST(1 as int) AS Rst_sort, "+; "cnt_color = CASE WHEN prs_color = 0 THEN CAST(16777215 as int) ELSE prs_color END "+; "FROM t_mainroster "+; "INNER JOIN t_persons ON prs_pk = rst_persfk "+; "WHERE rst_startdate <=?(dDateTo+1) AND (rst_enddate >= ?dDate OR rst_enddate < '19100101') "+; "UNION " +; "SELECT DISTINCT CONVERT(char(80), RTRIM(prs_lastname)+', '+RTRIM(prs_firstname)+' '+prs_prefix) as Source, "+; "CONVERT(Int, apt_persfk*2) AS ID, CAST(0 AS Int) AS Rst_dr_id, apt_Persfk AS Rst_persfk, CAST(1 as int) AS Rst_sort, "+; "cnt_color = CASE WHEN prs_color = 0 THEN CAST(16777215 as int) ELSE prs_color END "+; "FROM t_apptment "+; "INNER JOIN t_Persons ON apt_persfk = prs_pk "+; "WHERE Apt_appdate BETWEEN ?dDate AND ?(dDateTo+1) AND apt_persfk <> 0 " SQLEXEC(applic.SqlHandle, cString1, "Res1") SQLEXEC(applic.SqlHandle, cString2, "Res2") ** all doctors and resources in one list. To make a distinction between a doctor and resource, ; the doctor is an even number, a resource and odd numbers. their original PK can be determine by dividing by it by two SELECT * FROM Res1 UNION SELECT * FROM res2 INTO CURSOR Doctors ** Get the parameters for the views and queries nDr_id = IIF(doctors.rst_sort=2 AND THISFORM.nView # 2, doctors.rst_dr_id,0) nPersfk= IIF(doctors.rst_sort=1 AND THISFORM.nView # 2, doctors.rst_persfk,0) REQUERY("apptlist") REQUERY("Apptnotes") ** All data is there now do the datamunging. ** Now depending on the selected layout of the view, mung it into the appropriate form for display and reporting. DO CASE CASE THISFORM.nView=1 THISFORM.GetDailyDrView(dDate) CASE THISFORM.nView=2 THISFORM.GetDailyView(dDate) CASE THISFORM.nView=3 SELECT apptlist THISFORM.Getweeklyview(dDate) CASE THISFORM.nView=4 SELECT apptlist THISFORM.Get4weeklyview(dDate) ENDCASE *- ** An example of the GetWeeklyview method FUNCTION Getweeklyview LPARAMETERS dDate ** Create the resultset. IF !USED("WeeklyView") cCommand = "CREATE CURSOR WeeklyView (Time C(5), DispTime C(10)" FOR nT = 1 TO 7 cPrefix="_"+ALLTRIM(STR(nT)) cCommand = cCommand + ", "+cPrefix+"_Patient C(50), "+cPrefix+"_pk I, "+cPrefix+"_Color I, "+cPrefix+"_Style N(1)" ENDFOR cCommand = cCommand + ")" SELECT 0 &cCommand ELSE SELECT WeeklyView ZAP ENDIF INDEX ON Time TAG cTime ** Now insert all timeslots as specified by the roster. Each roster can create multiple records in the resultset. ** See DO WHILE FOR nT = 1 TO 7 && days of the week SELECT Mainroster cWhere = IIF(doctors.rst_sort=1, "rst_persfk = doctors.rst_persfk", "Rst_dr_id = Doctors.Rst_dr_id") + ; " AND Rst_"+GETWORDNUM("mon Tues Wednes Thurs fri Satur sun",DOW(dDate+nT-1,2))+"Day" SELECT MainRoster SCAN FOR rst_Timeslot # 0 AND BETWEEN(dDate+nT-1,rst_startdate,rst_enddate) AND &cWhere tStart=CTOT(DTOC(dDate) +" "+ Mainroster.rst_StartTime) tEnd=CTOT(DTOC(dDate) +" "+ Mainroster.rst_EndTime) tTime=tStart DO WHILE tTime < tEnd cTime = TTOC(tTime,2) IF !SEEK(cTime,"WeeklyView") INSERT INTO WeeklyView (Time) VALUES (cTime) ENDIF tTime=tTime + MainRoster.rst_Timeslot * 60 ENDDO ENDSCAN ENDFOR THISFORM.RefreshWeeklyView(dDate, "Weeklyview", 7) ** Code to populate grid etc... FUNCTION Refreshweeklyview LPARAMETERS dDate, cAlias, nDays LOCAL nSec, nT, cFieldsList cAlias = EVL(cAlias, "WeeklyView") nDays = EVL(nDays, 7) #DEFINE STYLE_NOROSTER 0 #DEFINE STYLE_APPOINTMENT 1 #DEFINE STYLE_BLACKOUT 2 #DEFINE STYLE_AVAILABLE 3 #DEFINE STYLE_MEETING 4 #DEFINE STYLE_BLOCKED 5 #DEFINE STYLE_OBSOLETE 6 #DEFINE STYLE_DOUBLEBOOK 7 #DEFINE STYLE_ADDEDTIMESLOT 8 #DEFINE COLOR_NOROSTER THISFORM.BackColor #DEFINE COLOR_APPOINTMENT RGB(255,255,223) #DEFINE COLOR_BLACKOUT RGB(255,0,0) #DEFINE COLOR_AVAILABLE RGB(255,255,255) #DEFINE COLOR_MEETING RGB(128,255,128) #DEFINE COLOR_BLOCKED RGB(192,0,0) #DEFINE COLOR_OBSOLETE THISFORM.BackColor #DEFINE COLOR_ADDEDTIMESLOT RGB(255,255,223) LOCAL aColors[9] aColors[STYLE_NOROSTER+1] = COLOR_NOROSTER aColors[STYLE_APPOINTMENT+1] = COLOR_APPOINTMENT aColors[STYLE_BLACKOUT+1] = COLOR_BLACKOUT aColors[STYLE_AVAILABLE+1] = COLOR_AVAILABLE aColors[STYLE_MEETING+1] = COLOR_MEETING aColors[STYLE_BLOCKED+1] = COLOR_BLOCKED aColors[STYLE_OBSOLETE+1] = COLOR_OBSOLETE aColors[STYLE_ADDEDTIMESLOT+1] = COLOR_ADDEDTIMESLOT nSec = SECONDS() SELECT 0 USE (DBF(cAlias)) AGAIN ALIAS Weekly2 ORDER 1 cFieldList="" FOR nT = 2 TO FCOUNT() cFieldList = cFieldList + IIF(!EMPTY(cFieldList),", ","")+FIELD(nT) ENDFOR BLANK FIELDS &cFieldList ALL ** Scan trough all appointments and insert them into Weekly2. SELECT Apptlist SCAN FOR !EMPTY(apt_apptime) AND (!EMPTY(Apptlist.apt_dr_id) OR !EMPTY(Apptlist.apt_persfk)) AND INLIST(apt_status, 0, 1, 2, 4) cPrefix = "_"+ALLTRIM(STR(apt_appdate - dDate + 1)) cPkColumn = cPrefix+"_pk" SELECT Weekly2 SEEK Apptlist.apt_apptime LOCATE WHILE Time = STRTRAN(Apptlist.apt_apptime,".",":") FOR EMPTY(&cPkColumn) OR EVALUATE(cPrefix+"_Style") = 8 IF !FOUND() ** The timeslot was not available yet, so insert a new timeslot INSERT INTO Weekly2 (Time) VALUES (STRTRAN(Apptlist.apt_apptime,".",":")) ENDIF ** Misusing the color column to store the lenght of the appointment ** in order to, later when all appointments are stored, set all rows falling ** within the timeframe of the appointment to the correct values. DO CASE CASE apptlist.apt_Acu_id = "meet" ** A meeting as specified in the appointment table REPLACE (cPkColumn) WITH apptlist.apt_pk,; (cPrefix+"_Patient") WITH GetCaption("PATCHLABELS.MEETING"),; (cPrefix+"_Color") WITH IIF(Apptlist.apt_wholeday, -1, MAX(apptlist.apt_Length,1)),; (cPrefix+"_Style") WITH STYLE_MEETING CASE apptlist.apt_Acu_id = "black" ** A blackout as specified in the appointment table REPLACE (cPkColumn) WITH apptlist.apt_pk,; (cPrefix+"_Patient") WITH GetCaption("CAPTION.BLOCKED"),; (cPrefix+"_Color") WITH IIF(Apptlist.apt_wholeday, -1, MAX(apptlist.apt_Length,1)),; (cPrefix+"_Style") WITH STYLE_BLOCKED CASE apptlist.apt_Acu_id = "roster" ** a roster change as specified in the appointments table. tStart=CTOT(DTOC(dDate) +" "+ Apptlist.apt_apptime) tEnd= tStart + 300 * Apptlist.apt_length tTime=tStart SELECT list LOCATE FOR ItemId = apptlist.apt_itemid SELECT Weekly2 DO WHILE tTime < tEnd cTime = LEFT(TTOC(tTime,2),5) DO CASE CASE !SEEK(cTime,"Weekly2") INSERT INTO Weekly2 (Time, (cPkColumn), (cPrefix+"_Style") ) ; VALUES (cTime, apptlist.apt_pk, 8) CASE EMPTY(NVL(EVALUATE("Weekly2."+cPkColumn),0)) REPLACE (cPkColumn) WITH apptlist.apt_pk,; (cPrefix+"_Style") WITH 8 ; IN Weekly2 ENDCASE tTime=tTime + MAX(apptlist.apt_roster_id,5) * 60 ENDDO = SEEK(TTOC(tStart,2),"Weekly2") REPLACE (cPrefix+"_Color") WITH IIF(Apptlist.apt_wholeday, -1, MAX(apptlist.apt_Length,1)) IN weekly2 CASE apptlist.apt_Acu_id = "notes" ** notes for today ** do nothing as this has no impact in the timeslots OTHERWISE ** A regular appointment IF THISFORM.Showproc SELECT list && remote view, loaded only once LOCATE FOR ItemId = apptlist.apt_itemid SELECT Weekly2 cPatient= IIF(EMPTY(Apptlist.apt_arrtime),"","*")+; ALLTRIM(List.Procedure)+; IIF(EMPTY(Apptlist.apt_Confirmed),""," +") ELSE cPatient= IIF(EMPTY(Apptlist.apt_arrtime),"","*")+; Applic.GetDemoName(apptlist.apt_Acu_id)+; IIF(EMPTY(Apptlist.apt_Confirmed),""," +") ENDIF REPLACE (cPkColumn) WITH apptlist.apt_pk,; (cPrefix+"_Patient") WITH cPatient,; (cPrefix+"_Color") WITH MAX(apptlist.apt_Length,1),; (cPrefix+"_Style") WITH STYLE_APPOINTMENT ENDCASE ENDSCAN ** If the view is empty, just insert one record (9:00 to be able to add appointments) IF RECCOUNT("Weekly2") = 0 INSERT INTO Weekly2 (Time) VALUES ("09:00") ENDIF ** Mark all timeslots within each roster as avaliable, except for those that have been occupied by the ; ** Appointments nColor=THISFORM.BackColor SELECT Mainroster nDr_id= VAL(THISFORM.Doctorid) FOR nT = 1 TO nDays cWhere = IIF(doctors.rst_sort=1, "rst_persfk = doctors.rst_persfk", "Rst_dr_id = Doctors.Rst_dr_id") + ; " AND Rst_"+GETWORDNUM("monday Tuesday Wednesday Thursday friday Saturday sunday",DOW(dDate+nT-1,2)) SCAN FOR rst_Timeslot # 0 AND BETWEEN(dDate+nT-1, rst_StartDate, rst_EndDate) AND &cWhere cPrefix = "_"+ALLTRIM(STR(nT)) cColumn = cPrefix+"_Style" cColumn2= cPrefix+"_Patient" REPLACE ALL (cColumn) WITH STYLE_AVAILABLE, ; (cColumn2) WITH NVL(mainroster.lst_procedure,"") ; FOR time >= Mainroster.rst_StartTime AND time < Mainroster.rst_EndTime ; AND EMPTY(&cColumn) IN Weekly2 ENDSCAN ENDFOR ** Get the blackout data and apply them to the roster SELECT Blk FOR nT = 1 TO nDays cWhere = IIF(doctors.rst_sort=1, "blk_persfk = doctors.rst_persfk", "blk_dr_id = Doctors.Rst_dr_id")+; " AND blk_"+GETWORDNUM("Mon Tue Wed Thu Fri Sat Sun",DOW(dDate+nT-1,2)) SCAN FOR BETWEEN(dDate+nT-1, blk.blk_StartDate, blk.blk_EndDate) AND &cWhere cPrefix = "_"+ALLTRIM(STR(nT)) cColumn = cPrefix+"_Style" REPLACE ALL (cColumn) WITH STYLE_BLACKOUT ; FOR Blk.Blk_allday OR (time >= blk.blk_StartTime AND time < blk.blk_EndTime) ; AND !EMPTY(&cColumn) IN Weekly2 ENDSCAN ENDFOR ** Mark subsequent timeslots also used for an appointment or blackout. STORE 0 TO nRed, nGreen, nBlue =RGBComp(Doctors.cnt_color ,@nRed, @nGreen, @nBlue) nDimColor=RGB(.75 * nRed, .75*nGreen, .75*nBlue) && create a dim colour for overlapping appointments aColors[STYLE_DOUBLEBOOK+1]=nDimColor FOR nT = 1 TO nDays SELECT Weekly2 cPrefix = "_"+ALLTRIM(STR(nT)) cColumn = cPrefix+"_pk" LOCATE FOR !EMPTY(&cColumn) DO WHILE !EOF() nLength = EVALUATE(cPrefix+"_Color") cEndtime = TTOC(CTOT(DTOC(DATE())+" "+Time)+nLength * 300,2) nStyle = IIF(EVALUATE(cPRefix+"_Style")=STYLE_DOUBLEBOOK, STYLE_APPOINTMENT, EVALUATE(cPrefix+'_Style')) nPk = EVALUATE(cPrefix+"_Pk") SKIP nRecNo = IIF(EOF(),0,RECNO()) ** Make sure that following timeslots during the apointment are marked as belongin to the appointment IF nLength = -1 ** Whole day for blocked and meetings cCommand = 'REPLACE '+cPRefix+'_Style WITH nStyle, '+; cPrefix+'_Pk WITH nPk, '+; cPrefix+'_Patient WITH "..." '+; 'WHILE .T. FOR INLIST('+cPrefix+'_Style, 0, 3,8) OR (INLIST('+cPrefix+'_Pk, nPk, 0) OR '+; cPrefix+'_Patient = "...")' ELSE ** Appointments/blocked timeslots/meetings that have a limited lenght. cCommand = 'REPLACE '+cPRefix+'_Pk WITH IIF(INLIST('+cPrefix+'_Pk, nPk, 0) OR '+cPrefix+; '_Patient = "..." OR '+cPrefix+'_Style = 8,nPk, '+cPrefix+'_pk),'+; cPrefix+'_Style WITH IIF(INLIST('+cPrefix+'_Style, 1,8) and nStyle <> 8, IIF(nStyle = 1 and '+cPrefix+'_Style = 1,7, 1), '+; 'IIF(INLIST('+cPrefix+'_Pk, nPk, 0) OR '+cPRefix+'_Patient = "...", nStyle, '+; cPRefix+'_Style)), '+; cPrefix+ '_Patient WITH IIF(nStyle <> 8 AND (INLIST('+cPrefix+'_Pk, nPk, 0) OR '+cPrefix+'_Patient = "..."), '+; 'IIF('+cPrefix+'_Patient="...","----- double booked -----","..."), '+cPrefix+'_Patient) '+ ; 'WHILE Time < cEndTime' ENDIF &cCommand IF nRecno # 0 GO nRecNo ENDIF cPk = cPrefix+"_pk" LOCATE FOR !INLIST(&cPk, 0, nPk) REST ENDDO cCommand = 'REPLACE ALL '+cPrefix+'_Color WITH IIF('+cPRefix+'_Style = 1, Doctors.cnt_color ,aColors['+; cPrefix+'_style+1]),'+cPrefix+'_Patient WITH IIF('+cPrefix+'_Patient = "...","",'+cPrefix+'_Patient)' &cCommand ENDFOR ** display the time in 12 hour format (AM/PM) SELECT Weekly2 IF Settings.Hourformat = 12 SET HOURS TO 12 ELSE SET HOURS TO 24 ENDIF REPLACE ALL DispTime WITH TTOC(CTOT(DTOC(DATE())+" "+STRTRAN(Time,".",":")),2) IN Weekly2 SET HOURS TO 24 USE IN Weekly2 RETURN