Thank you both very much for your help. I kind of like your solution Klatuu.
I just didn't know about the idea of having the code loop while waiting for
user input. Is this acceptable in developing? Does it chew system resources?
Ultimately I ended up adding a column to the tech table as boolean that gets
selected whenever the tech is selected on the "create timesheets" form and
cleared back to false whenever the form is closed. Then based on that i
generate a recordset and create a report for each record. Here is the code
incase you would like to see it:
Sub CreateTimeSheets(constView As AcView)
On Error GoTo ErrorHandler
Dim cnn1 As ADODB.Connection
Dim myRecordSet As New ADODB.Recordset
Dim mySQLtech As String
Dim varTechName As String
Dim datWeekEnd As Date
Dim strPay As String
'create connection
Set cnn1 = CurrentProject.Connection
'create recordset
myRecordSet.ActiveConnection = cnn1
'create SQL string to select only desired technicians
Dim mySQL As String
mySQL = "SELECT [tblTechs].[techID], [tblTechs].[First Name],
[tblTechs].[Last Name] FROM tblTechs"
mySQL = mySQL & " WHERE tblTechs.CreateTimeSheet = True"
'open recordset with desired technician ids included
myRecordSet.Open Source:=mySQL, CursorType:=adOpenStatic
'check for error condition and exit sub if error will result
If myRecordSet.RecordCount = 0 Then
MsgBox "No technicians are selected", vbOKOnly
Exit Sub
End If
'get date from form and decide whether or not to filter
'on the date in the txtbox
If IsNull([Forms]![frmtimesheet].[txtWeekEnd]) Then
mySQLtech = "SELECT [tblSvcOrdersDet].[paid],
[tblSvcOrdersDet].[DateWorked], [tblSvcOrdersDet].[SvcOrder], " _
& "[tblSvcOrders].[ClassID], [tblSvcOrders].[Customer],
[tblSvcOrdersDet].[Reg Hours], " _
& "[tblSvcOrdersDet].[OT Hours], [tblSvcOrders].[JobNumber],
[tblSvcOrders].[SODate], [tblSvcOrdersDet].[tech] " _
& "FROM tblSvcOrders INNER JOIN tblSvcOrdersDet ON
tblSvcOrders.SvcOrder=tblSvcOrdersDet.SvcOrder " _
& "WHERE [tblSvcOrdersDet].[tech] = "
Else
datWeekEnd = [Forms]![frmtimesheet].[txtWeekEnd]
mySQLtech = "SELECT [tblSvcOrdersDet].[paid],
[tblSvcOrdersDet].[DateWorked], [tblSvcOrdersDet].[SvcOrder], " _
& "[tblSvcOrders].[ClassID], [tblSvcOrders].[Customer],
[tblSvcOrdersDet].[Reg Hours], " _
& "[tblSvcOrdersDet].[OT Hours], [tblSvcOrders].[JobNumber],
[tblSvcOrders].[SODate], [tblSvcOrdersDet].[tech] " _
& "FROM tblSvcOrders INNER JOIN tblSvcOrdersDet ON
tblSvcOrders.SvcOrder=tblSvcOrdersDet.SvcOrder " _
& "WHERE [tblSvcOrdersDet].[DateWorked] BETWEEN #" & CDate(DateAdd("d",
-6, datWeekEnd)) & "# AND #" _
& CDate(datWeekEnd) & "# And [tblSvcOrdersDet].[tech] = "
End If
'set variable for filtering based on paid or unpaid status
If [Forms]![frmtimesheet].[chkUnpaid] = False And
[Forms]![frmtimesheet].[chkPaid] = False Then
MsgBox "No records selected. Please select either Unpaid or Paid or
Both.", vbOKOnly
Exit Sub
ElseIf [Forms]![frmtimesheet].[chkUnpaid] = True And
[Forms]![frmtimesheet].[chkPaid] = False Then
strPay = " AND [tblsvcordersdet].[paid] = false"
ElseIf [Forms]![frmtimesheet].[chkUnpaid] = False And
[Forms]![frmtimesheet].[chkPaid] = True Then
strPay = " AND [tblsvcordersdet].[paid] = true"
Else
strPay = ""
End If
For i = 0 To myRecordSet.RecordCount - 1
DoCmd.OpenReport "rptTimeSheet", acViewDesign, windowmode:=acHidden
Reports("rptTimeSheet").RecordSource = mySQLtech & myRecordSet.Fields(0)
& strPay & ";"
Reports("rptTimeSheet").txtTechName.ControlSource = "=DLookup(""[First
Name]"", " _
& """[tblTechs]"", ""[techid]=" & myRecordSet.Fields(0) & """) & "" ""
& DLookup(""[Last Name]"", " _
& """[tblTechs]"", ""[techid]=" & myRecordSet.Fields(0) & """)"
DoCmd.Close acReport, "rptTimeSheet", acSaveYes
DoCmd.OpenReport "rptTimeSheet", constView, windowmode:=acDialog
myRecordSet.MoveNext
Next
'remove used objects from memory
Set myRecordSet = Nothing
Set cnn1 = Nothing
If IsOpen("rptTimeSheet", acReport) Then DoCmd.Close acReport,
"rptTimeSheet"
Exit Sub
ErrorHandler:
' Display error information.
MsgBox "Error number " & Err.Number & ": " & Err.Description
' Resume with statement following occurrence of error.
Exit Sub
End Sub
Klatuu said:
This was an interesting enough post that I had to set up a test environment
and see what it would take. Here is what I came up with.
First, you don't need a different SQL statement for each employee. You just
use one unfiltered query. The filtering is done using the Where arguemnet of
the OpenReport method. You do need a list of all the employees that will be
included so the code can loop through all of them. They way I did that was
using a query as a one column recordset. The column is the name of the field
that I want the reports ordered by. If there is other filtering criteria,
you would need to add it to this query and remove it from the report's record
source query.
The code is behind a command button that starts the process and opens the
first report filtered by the first employee. It then just sits and loops
until you close the report, then it moves to the next record and opens the
report for the next query. It does that until it has presented each report
or if you click another button the form to cancel the reports.
****************************************
Dim blnCancelReport As Boolean
Private Sub Command2_Click()
Dim rst As DAO.Recordset
Dim rpts As AllReports
blnCancelReport = False
Set rst = CurrentDb.OpenRecordset("SELECT MainName, " & _
"ClientID FROM tblClient ORDER BY MainName;")
Set rpts = CurrentProject.AllReports
With rst
Do While Not .EOF And Not blnCancelReport
DoCmd.OpenReport "Report2", acViewPreview, , "[ClientID] = " &
!ClientID
Do Until Not rpts("Report2").IsLoaded
DoEvents
If blnCancelReport Then
DoCmd.Close acReport, "Report2", acSaveNo
Exit Do
End If
Loop
.MoveNext
Loop
.Close
End With
Set rst = Nothing
Set rpts = Nothing
End Sub
Private Sub Command4_Click()
blnCancelReport = True
End Sub
************************************
If you have any questions on this, post back.
--
Dave Hargis, Microsoft Access MVP
Preston said:
Hi,
I have a question about making a report in VBA. I have a db of tech hours
that I need to make timesheets from once a week. In making the timesheets I
have generated a recordset of selected techs that the code loops through and
makes a timesheet for each one by changing the reports recordsource to a new
sql statement. The problem I am having is that the code doesn't wait for any
input or user interaction before wiping the previous report and generating
the next one. I want the code to wait in preview mode until the report is
closed or printed and then generate the next timesheet. Is there a way to do
this? I have used a msgbox in the loop for each tech but that seems like a
duct tape solution and the msgbox pops up in the middle of the screen. Can i
have the code wait for the report to be closed before generating the next
report in the series?
Thank you for any help you can give on this problem.
Preston