ClinPlus Data Management V3.0
Report Examples
Past Due Pages Report
Description
The Past-Due Pages report displays a list of pages that have not been tracked in and are considered past due based on their definition and milestone date. This report corrects a bug in Due Group processing in the system supplied Past Due Pages report, includes logic to consider the Effective Discontinue Date as entered in the Patients editor, displays additional columns and requires less time and resources to execute.
This version of the Past Due Pages report should be used in place of the Past Due Pages report supplied in version 3.21(SR-3) and earlier.
Sample Output

Instructions for adding the report programs
Code Example
Report Examples
Past Due Pages Report
Description
The Past-Due Pages report displays a list of pages that have not been tracked in and are considered past due based on their definition and milestone date. This report corrects a bug in Due Group processing in the system supplied Past Due Pages report, includes logic to consider the Effective Discontinue Date as entered in the Patients editor, displays additional columns and requires less time and resources to execute.
This version of the Past Due Pages report should be used in place of the Past Due Pages report supplied in version 3.21(SR-3) and earlier.
Sample Output

Instructions for adding the report programs
- Copy or Save the attached program code where it will be accessible to import
- Go to System Administration
- Go to Report Library
- Add a new report
- Enter a name for the report (Past Due Pages)
- Select Type = Normal Specify a Category (Tracking)
- Click Import and browse to the program file
- Select program and click Open
- The Code Changes Exist field should now say 'Yes' Click Save on the Report Library Window
- Click Go Back to return to the Reports menu
- Define the Report Template(s)
- Go to Report Templates
- Add a new Template
- Enter a name in the name input field (Non-Verified Records)
- Select the level for the report as Global (available to all studies) in the
- Studies level selection box
- Specify a description for the report
- Specify a Category (Tracking)
- Set Report Type = Current Study Only
- In the program field, browse to select the program defined above
- There is no pre processing or post processing program to specify
- In the Selection criteria paste or set the following two entries to provide Investigator/Patient selections:
- Data set = PVIEWS.ENROLLMENT
- Variable = INVESTIGATORNUMBER
- Selection Label = Investigator Number
- Dependant = N/A
- Type = Multiple
---------------------------------- - Data set = PVIEWS.ENROLLMENT
- Variable = PATIENTNUMBER
- Selection Label = Patient Number
- Dependant = Yes
- Type = Multiple
- On the output tab, set the layout to Landscape
- To set a custom output such as HTML as opposed to the default SAS Output, on the output tab and set the following:
- Layout = Landscape
- Check 'Use ODS' Type = HTML or RTF or PDF (for rtf or pdf you need to have word or acrobat installed on the server)
- Set the desired style. RTF or Printer works well
Code Example
Code:
/*****************************************************\ Program past_due_pages.sas Description: Generates a list of pages that are past due Changes: 10-24-2007 G. Wagner Cached pages, tracking and enrollment to work directory. Changed all program references from pview. to pv_ Added missing by statement in data step work._invspats on 01/18/08 B. Borysko Re-written to improve efficiency. Fixed Due Group processing Allowed report to be generated on Due Groups when no milestone dates are present. Added Page Type and Due Group columns. 11/04/08 B. Borysko Will include the effective discontinue date from the Enrollments view when determining a discontinue date \*****************************************************/ options mprint; %macro getkeyDates(i); %if &&keydata&i>'' and &&keyvar&i>'' %then %do; data keyDates(keep=InvestigatorNumber PatientNumber keyDateNumber keyDate); set keyDates pviews.&&keydata&i.&&keycriteria&i; if newRecord then do; keyDateNumber=left(put(&i,2.)); keyDate=&&keyvar&i; if keydate>. then output; end; else output; run; %if &i=1 %then %do; data firstKeyDates(keep=InvestigatorNumber PatientNumber firstKeyDate); set pviews.&&keydata&i.&&keycriteria&i; firstKeyDate=&&keyvar&i; if firstKeydate>. then output; run; %end; %end; %mend; %macro getDiscDates; data discDates; length InvestigatorNumber PatientNumber $50 discdate 8; stop;run; %if &discData>'' and &discVar>'' %then %do; data discDates(keep=InvestigatorNumber PatientNumber discDate); set discDates pviews.&discData&discCriteria; if newRecord then do; discDate=&discVar; if discDate>. then output; end; else output; run; %end; ** Get effective discontinue date **; data eff_disc(keep=InvestigatorNumber PatientNumber effectiveDiscDate); set pviews.enrollment(where=(effectiveDiscDate>.)); proc sort;by InvestigatorNumber PatientNumber; data discDates(drop=effectiveDiscDate);merge eff_disc(in=a) discDates(in=b); by InvestigatorNumber PatientNumber; ** actual discontinue date overrides effective discontinue date; if a and ^b then discDate=effectiveDiscDate; run; %mend; %macro cleanup(ds); %if %sysfunc(exist(&ds)) %then %sysfunc(delete(&ds)); %mend; ** Define macro to produce report and check if there is any output **; %macro report; %let dupdisc=0; %let dupkeys=0; %let dsid1 = %sysfunc(open(psys._studyinformation(&spw),i)); %if &dsid1 %then %do; %let rc=%sysfunc(fetch(&dsid1)); %let protokey=%sysfunc(getvarn(&dsid1,1)); %let dsid1=%sysfunc(close(&dsid1)); %end; proc sort data=pv_enrollment;by investigatorNumber patientNumber; *** Get Milestone dates ***; data keyDates; length InvestigatorNumber PatientNumber $50 keyDateNumber $2 firstKeyDate keyDate 8; stop;run; data firstKeyDates; length InvestigatorNumber PatientNumber $50 firstKeyDate 8; stop;run; data _null_; array keydatedataset {10} $50 keydatedataset1-keydatedataset10; array keydatevar {10} $50 keydatevar1-keydatevar10; array keydatedescription {10} $50 keydatedescription1-keydatedescription10; array keydatecriteria {10} $150 keydatecriteria1-keydatecriteria10; set cpglobal._keydates(where=(_parentkey=&protokey) &gpw); do i=1 to 10; if keydatedataset{i}>'' and keydatevar{i}>'' then do; if keydatecriteria{i}>'' then criteria='(where=('||keydatecriteria{i}||') in=newrecord)'; else criteria='(in=newrecord)'; call symput('keydata'||left(put(i,2.)),keydatedataset{i}); call symput('keyvar'||left(put(i,2.)),keydatevar{i}); call symput('keycriteria'||left(put(i,2.)),criteria); end; else do; call symput('keydata'||left(put(i,2.)),''); call symput('keyvar'||left(put(i,2.)),''); end; end; call symput('discData',discontinueDateDataSet); call symput('discVar',discontinueDateVar); if discontinueDateCriteria>'' then criteria='(where=('||discontinueDateCriteria||') in=newrecord)'; else criteria='(in=newrecord)'; call symput('discCriteria',criteria); run; %getKeyDates(1); %getKeyDates(2); %getKeyDates(3); %getKeyDates(4); %getKeyDates(5); %getKeyDates(6); %getKeyDates(7); %getKeyDates(8); %getKeyDates(9); %getKeyDates(10); %getDiscDates; proc sort data=keyDates nodupkey;by investigatorNumber patientNumber keyDateNumber keydate; proc sort data=firstkeyDates nodupkey;by investigatorNumber patientNumber; data keydates;merge keydates firstkeyDates;by investigatorNumber patientNumber; proc sort data=discDates nodupkey;by investigatorNumber patientNumber discdate; *** Check for duplicate key dates/investigatorNumber/PatientNumber/KeyDateNumber ***; Data _null_;set keydates end=eof;by investigatorNumber patientNumber keyDateNumber; retain dupkeys 0; if not first.keyDateNumber then do; call symput('dupKeys',1); call symput('dupKeyDateNumber',keyDateNumber); call symput('dupinvestigatorNumber',investigatorNumber); call symput('dupPatientNumber',patientNumber); stop; end; if eof then call symput('dupKeys',dupkeys); run; *** Check for duplicate discontinue dates/investigatorNumber/PatientNumber***; Data _null_;set discdates end=eof;by investigatorNumber patientNumber; retain dupDisc 0; if not first.patientNumber then do; call symput('dupDisc',1); call symput('dupinvestigatorNumber',investigatorNumber); call symput('dupPatientNumber',patientNumber); stop; end; if eof then call symput('dupDisc',dupDisc); run; ** Duplicate key or disc dates found**; %if &dupkeys=1 or &dupDisc=1 %then %do; data work.report(KEEP=information); length Information $500; information="Multiple milestone dates/patient/milestone were found."; output; information="Error triggered by:"; output; information=''; output; %if &dupkeys=1 %then %do; information="Key Date Number=&dupKeyDateNumber"; %end; %else %do; information="Key Date Number=Discontinue Date"; %end; output; information="Investigator Number=&dupInvestigatorNumber"; output; information="Patient Number=&dupPatientNumber"; output; information=''; output; information="Check you milestone date criteria in Study Administration."; output; run; proc print noobs data=work.report; run; %end; %else %do; proc sort data=pv_tracking;by investigatorNumber patientNumber pageNumber; data pv_enrollment; set pviews.enrollment; run; ** Create an entire case book for each patient **; %cpsubset(pv_enrollment); proc sort data=pv_enrollment;by investigatorNumber patientNumber; data CaseBooks;set pv_enrollment; do obsnum=1 to last; set pv_pages point=obsnum nobs=last; output; end; run; *** Get Due Group In House dates; data dueGroups;set caseBooks(where=(type in('G','S'))keep=investigatorNumber PatientNumber pagenumber type dueGroup); proc sort data=dueGroups;by investigatorNumber PatientNumber PageNumber; data dueGroups;merge dueGroups(in=wanted) pv_tracking(keep=investigatorNumber PatientNumber PageNumber inHouseDate); by investigatorNumber PatientNumber PageNumber; if wanted; if inHouseDate>.; proc sort data=dueGroups;by investigatorNumber PatientNumber dueGroup inHouseDate; data dueGroups(drop=pageNumber rename=(inHouseDate=DueGroupTriggerDate)); set dueGroups; by investigatorNumber PatientNumber dueGroup inHouseDate; if first.dueGroup; run; proc sort data=casebooks;by investigatorNumber PatientNumber dueGroup; data casebooks;merge casebooks dueGroups;by investigatorNumber PatientNumber dueGroup; run; ** merge in mileStone and discontinue dates **; proc sort data=casebooks;by investigatorNumber PatientNumber keyDateNumber; data casebooks(where=(keyDate>. or dueGroupTriggerDate>.));merge casebooks(in=wanted) keyDates(drop=firstKeyDate);by investigatorNumber PatientNumber keyDateNumber; if wanted; data caseBooks;merge casebooks(in=wanted) keyDates(keep=investigatorNumber PatientNumber firstKeyDate); by investigatorNumber PatientNumber; if wanted; data casebooks; merge casebooks(in=wanted) discDates;by investigatorNumber PatientNumber; if wanted; run; %cpwhere(casebooks); proc sort data=casebooks;by investigatorNumber patientNumber pageNumber; data report;merge caseBooks pv_tracking(in=Tracked); by investigatorNumber patientNumber pageNumber; if not tracked; select(type); when('N') duedate=keyDate+period; when('G') duedate=dueGroupTriggerDate; when('S') duedate=dueGroupTriggerDate+period; when('P') duedate=firstKeyDate+period; when('A') duedate=firstKeyDate+period; when('D') duedate=KeyDate+period; otherwise delete; end; if discDate>. and discdate. and duedate