Multi-Page vs Multi-PDF Loop problems - ms-access

I have a form that contains multiple partners that share a "pool". The partners are listed on a subform. After I'm done entering the information, I want a button to run a report for each of the partners with their specific information. But since it's multiple partners and I need one report for each (which I then want to email), I want to use a Loop to go through each of the partners.
EDIT1: Added entire code for review. I do have Option Explicit in and I have compiled it as well.
Private Sub btn_Run_Click()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
strSQL = "Select * FROM Cobind_qryReport WHERE PartPoolName = """ & Me.TopLvlPoolName & """"
Debug.Print "strSQL: " & strSQL
Set db = CurrentDb
Set rs = db.OpenRecordset(strSQL)
On Error GoTo Err_PO_Click
If MsgBox("Do you wish to issue the cobind invites?", vbYesNo + vbQuestion, "Confirmation Required") = vbYes Then
rs.MoveFirst
Do While rs.EOF = False
DoCmd.OutputTo acOutputReport, "Cobind_rptMain", acFormatPDF,_
"K:\OB MS Admin\Postage\CoBind Opportunities\Sent Invites\" _
& rs!CatCode & "_" & rs!PartPoolName "Cobind Invite_" & _
Format(Now(), "mmddyy") & ".pdf"
DoCmd.SendObject acSendReport, "Cobind_rptMain", acFormatPDF, ,_
, , " Cobind Invite", "Please find the cobind invite attached._
Response is needed by " & [RSVP] & ". Thank you.", True
rs.MoveNext
Loop
End If
Exit_PO_Click:
MsgBox ("It didn't work")
rs.Close
Set rs = Nothing
Set db = Nothing
Exit Sub
Err_PO_Click:
MsgBox Err.Description
Resume Exit_PO_Click
End Sub
This should allow me to create a report for each record in my query, save it to my server, then open an email to send it out. Right now, it appears that the [PartPoolName] is hanging up the code because I'm getting a "Microsoft Office Access can't find the field "|" referred to in your expression." If I take out the [PartPoolName], it'll create a PDF with four pages (each page showing a partner), where I want to end up with four separate PDFs.

The first thing you should do is add Option Explicit to the Declarations section of your module.
Then, from the Visual Basic editor's main menu, select Debug->Compile [your project name here]
Fix all the problems the compiler complains about. I suspect one of the compiler's first complaints may be triggered by this section of your code:
rs.MoveFirst
Do While Recordset.EOF = False
Do you have two recordset objects open, or one?
After you fix everything the compiler complains about, try your revised code.
If you get runtime errors, show us the exact error message and which code line is highlighted.
If the part of your code you haven't shown us includes an error hander, you can disable that error handler like so:
'On Error GoTo Err_PO_Click
Error handlers are great for production to shield users from errors. However, during development you really need to be able to identify which code line causes the error.
Alternatively, you can leave your error handler active and select Tools->Options from the editor's main menu. In the Options dialog, select the General tab, then select the "Break on All Errors" radio button and click OK. You can switch that option back to "Break on Unhandled Errors" after you finish your testing.
Update: You wrote: Right now, it appears that the [PartPoolName] is hanging up the code because I'm getting a "Microsoft Office Access can't find the field "|" referred to in your expression."
What is [PartPoolName]? If it's a field in the recordset, you can reference its value as rs!PartPoolName If it's something else, perhaps a global variable, give us more information about it.
Update2: Whenever your current code completes without error, you will hit this:
Exit_PO_Click:
MsgBox ("It didn't work")
Can that be right?
Update3: This OutputTo statement is your issue now, right?
DoCmd.OutputTo acOutputReport, "Cobind_rptMain", acFormatPDF,_
"K:\OB MS Admin\Postage\CoBind Opportunities\Sent Invites\" & _
"Cobind Invite_" & Format(Now(), "mmddyy") & ".pdf"
Cobind_rptMain is a report. It has a RowSource for its data. You're calling OutputTo with that report 4 times (once for each of the 4 rows in the recordset). Yet you expect 4 different versions of that report ... a separate report for each PartPoolName value?

To finish off the fine work by HansUp visit a page on how to print a report for a single record and how to generate reports to attach to emails. See the Emailing reports as attachments from Microsoft Access page.

Related

Access Run-time Error 2475 *occasionally* occuring

I have an error log that logs in the access table whenever a runtime error occurs for a user in the error trapper, and a particular error seems to occur for 10 random users, every hour at least.
This error appears to occur completely at random, on a random module with the Set ActiveForm code, with random users at random intervals. As far as I can see, there is no pattern between the users.
2475 - "You entered an expression that requires a form to be the active window".
This appears to occur in any of the modules that contain any of the setting of a form. I am using the following lines:
Dim af as Object
Set af = Screen.ActiveForm
I have tried using alternatives, such as declaring it as Form, and also tried the below:
Dim sstatus as String
Dim ps as String
If DLookup("[TM_UserType]", "[SD_Teams]", "[TM_username]= '" & usernm & "'") = "adj" Then
sstatus = "adj"
Else
sstatus = "tm"
End If
ps = "frmProdSubmit_" & sstatus
Then referencing the form this way:
Forms(ps).cmbTeam.Value = ""
But this still causes the same issue, even removing the ActiveForm part.
The last thing to mention (as I believe they could be factors) is that the front end is accessed through a shortcut, which minimises the Access window. Not sure if this could be the culprit, or if the user clicking another application can remove the focus.
The back-end of the database is also accessed by up to around 700 users each day.
As it stands, the error trapper pops up with the message, but the front end continues working correctly. It's just an annoying issue to resolve, but am slowly running out of ideas now, and any help would be hugely appreciated!
Error 2475 is thrown when a non-form object is the active screen object such as a table datasheet. I've encountered this error in an application that uses multiple instances of a form and needs to track whether the multiple form module is active or one of the other application module functions in which case all instances of the multiple forms (popups) need to have .visible set to false. I use the Screen.ActiveForm.Name call in the Form_Deactivate event.
You can trap the error in the procedure's error handler and take action knowing the screen's active object is not a form.
Example:
Private Sub Form_Deactivate()
On Error GoTo errHandler
If Screen.ActiveForm.Name <> "AnApplicationForm" Then 'throws 2475 if not a form object
sstatus = "status message"
End If
ExitSub:
Exit Sub
errHandler:
If Err.Number = 2475 Then Resume Next 'screen active object is not a form i.e. datasheet
MsgBox "Error in " & Me.Name & ".Form_Deactivate: " & Err.Number & " - " & Err.Description
Resume ExitSub
End Sub 'Form_Deactivate

DoCmd.OutputTo only works on break

I've come across a challenging problem with the DoCmd.OutputTo command in VBA Access 2013.
I've got below code which is basically to print a specific report from what is essentially a collection of records of reimbursements. The idea is that one would be able to [export] the active record (from the active form) to a PDF file and then add the scanned invoices to the PDF.
Thereto I would need to build the base file (i.e. the PDF where the invocies are added to) and then run the routine for adding the individual files.
Below code should create the initial PDF file:
Dim rpt as Report
filePath = "<some filepath>"
fName = Me!idDecl & " - (script).pdf"
filePath = filePath & fName
Set rpt = Report_qryDeclInvoice
With rpt
.Filter = "[fltID]= " & Me!id
.FilterOn = True
End With
DoCmd.OpenReport rpt.Name, acViewPreview, , "[fltID]= " & Me!id
DoCmd.OutputTo acOutputReport, rpt.Name, acFormatPDF, filePath, False
DoCmd.Close acReport, "qryDeclInvoice"
If I run the code -without breaks- the report opens as per the filtered argument, however, the subsequent command to output the record to PDF doesn't ?
That is, there appears a dialog box very briefly (can't read what it says) and then execution simply stops, no errors, no faultcodes just a clean break ?
Now for the interesting bit..
If I set a breakpoint on the DoCmd.OutputTo line, and execute the line with F8 the code works more or less flawlessly (see below)?? It appears that the break allows the preview routine to complete first and then run the OutputTo routine.
In addition to above challenge, on some of the reports (i.e. on some reimbursements) it works fine and the file is created yet on others it does not create the initial PDF at all and the code breaks without error codes or fault reporting. Without there being a distinguishable difference between the reports ?
I've tried delaying the OutputTo from the OpenReport function by sleeping it for 1000ms but that doesn't work (even upto 5000ms doesn't yield results)
Also if I remove the open preview line and just execute the OutputTo line, without opening the preview first, it works only when breaking and executing with F8 and again, only on some of the reports not all ?
It seems that the OutputTo command is -at least in my case- somewhat unreliable :-)
Any suggestions ??
OK, found out what was going on;
The faulty reports, that I mentioned, created multiple pages, based on grouping.
A section of VBA code in/on the report, re-created page numbers based on grouping (i.e. restarted page numbering for start of every group.) The execution of this VBA within the report (i.e. on open, or on page) interferes with the execution of the "OutputTo" routine. The above interfered with the OutputTo routine, causing it to break, though not sure why -yet-
Removal of all VBA code within the report solved the issue !!
Some added details:
No need for the preview anymore
set the filter of the report from VBA and open the report through the report object.name
Find below the working code:
Dim rpt as Report
filePath = "<somepath>"
fName = Me!idDecl & "-(script).pdf"
filePath = filePath & fName
'Debug.Print filePath
Set rpt = Report_qryInvoice
With rpt
.Filter = "[fltID]= " & Me!id
.FilterOn = True
End With
'Sleep (5000)
DoCmd.OutputTo acOutputReport, rpt.Name, acFormatPDF, filePath, False, , , acExportQualityScreen

MS Access - check sub-form before entry for duplicate

I've got a subform (customersAnswersSub) inside of a main form (customersAnswers). Upon someone entering a new customerAnswersSub entry - I wanted it to check for duplicates first.
It has to check across 4 different fields to match first.
This is what I've got so far.
Private Sub Form_BeforeUpdate(Cancel As Integer)
Dim rsGlobals As ADODB.Recordset
Dim sql
Set rsGlobals = New ADODB.Recordset
sql = "Select * From CustomerAnswerD where subscriptionNo=" & _
Me.subscriptionNo & " AND journal=" & Me.Journal & _
" AND volume=" & Me.volume & " AND issue=" & Me.issue
rsGlobals.Open sql, CurrentProject.Connection, adOpenDynamic, adLockOptimistic, adCmdText
If Not rsGlobals.BOF And Not rsGlobals.EOF Then
MsgBox ("Already entered")
Cancel = True
Me.Undo
End If
End Sub
it doesn't do anything - just sits there. when I close the form it'll pop up a - id already exists box.
Any idea, i'm pretty unexperienced when it comes to Access VB.
thank you
it doesn't do anything - just sits there
Just checking, since you said you're inexperienced with Access ... the form update event is not triggered until the record save is attempted. That may not happen automatically as soon as the user enters data into all the fields. However, you can trigger the update by navigating to a different record in the subform, or by a method such as choosing Records->Save Record from Access' (2003) main menu.
I don't see anything wrong with your BeforeUpdate procedure. Still I would convert it use the DCount() function instead of opening an ADO recordset. (See Access' help topic for DCount)
Private Sub Form_BeforeUpdate(Cancel As Integer)
Dim strCriteria As String
strCriteria = "subscriptionNo=" & Me.subscriptionNo & " AND journal=" & Me.Journal & _
" AND volume=" & Me.volume & " AND issue=" & Me.issue
Debug.Print strCriteria
If Dcount("subscriptionNo", "CustomerAnswerD", strCriteria) > 0 Then
MsgBox ("Already entered")
Cancel = True
Me.Undo
End If
End Sub
That assumes your table's subscriptionNo, journal, volume, and issue fields are all numeric data types. If any of them are text type, you will need to enclose the values in quotes within strCriteria.
I added Debug.Print strCriteria so you can view the completed string expression in the Immediate Window. You can also troubleshoot that completed string by copying it and pasting it into SQL View of a new query as the WHERE clause.
Also, consider adding a unique index on subscriptionNo, journal, volume, and issue to your CustomerAnswerD table design. That way you can enforce uniqueness without relying solely on your form to do it. The index will also give you faster performance with the DCount function, or your original recordset SELECT statement.
If you keep your original recordset approach, close the recordset and set the object variable = Nothing before exiting the procedure.

Corrupt Form - Rescue or Remake?

During my work on this database application, I've apparently managed to corrupt a form in the application - attempting to save any edit to any field on the form will cause Access to crash, and for the database file to report corrupted when Access attempts to re-open it.
I've tried exporting the entire form + controls as text, then re-importing them using VB code (from Allen Browne's website) but it will not re-import without either crashing Access or telling me the form isn't import-able due to an error (no error number or description given).
The form is rather complex, hence I am hesitant to just remake it from scratch, so is there a way to save it? If I do manage to recover it, does this mean I should transfer everything to a new MDB file (in case it's a cascading failure effect)?
To be honest, I've never managed to corrupt an Access database object before, so I don't know if this is something that signals the end of that MDB file, or just something I can correct and continue as before.
Decompile is a good thing to try once you've made a copy of the database. Have you tried saving the form under a different name using File >> Save As? Also try copying and pasting the form with a different name from the database window.
Also it's been my experience that one corrupt form/report does not spread to the rest of the database. That said it doesn't hurt to clean things up. Compact and repair only fixes up tables and related data such as indexes and relationships. To clean up corrupted other objects such as forms and reports you must import them into a new MDB/ACCDB. Tip: Close the database container window if you have a lot of objects. Access wastes a lot of time during the import refreshing the database container window.
What I ended up having to do was re-create the form, and copy element by element until I discovered that the strSupplierID combo box itself was the cause of the crashing. I re-created it from scratch, manually giving it the same properties, and replacing the VB from stored copies I cut and pasted to the clipboard. The form now works, and I removed the corrupted form, and compacted the database. Thanks for the help, everyone! :)
Others have supplied you with various approaches to possibly recover your corrupted form. Sometimes an code-bearing Access object will become irretrievably corrupt and none of these methods will work. In that case, you'll have to look= at backups to find a non-corrupt version as a starting point and import that and then revise it back to the current state of the object.
I'm posting an answer to suggest that you probably need to change your coding practices if you're encountering corruption in code-bearing objects.
First, you need to make sure you keep regular backups and do not overwrite them. Rolling back to an earlier version is always a last resort.
Always turn off COMPILE ON DEMAND in the VBE options. Read Michael Kaplan's article on The Real Deal on the Decompile Switch for the explanation of why.
In the VBE, add the compile button (and the call stack button) to your regular VBE toolbar, and hit that compile button after every few lines of code, and save your code.
Decide on a reasonable interval to backup and decompile your app. If you're doing heavy-duty code pounding, you might want to do this every day. If you've experienced an Access crash during coding, you likely want to make your backup and decompile/recompile. Certainly before distributing to users, you should decompile and recompile your app.
If you follow these practices, the causes of corruption in code-bearing Access objects will be minimized as much as possible, while you will also have plenty of backups (multiple levels of redundant backups are a must, because when backup failures happen, they almost always cascade through multiple levels -- have several types of backup and don't depend on an automatic backup).
But the key point:
Compile often, decompile reasonably often and icky stuff will never have a chance to accumulate in the p-code of your application.
Have you looked at the full set of methods for dealing with corruption from Allen Browne: http://allenbrowne.com/ser-47.html ? In particular, decompile.
It may be worth try a copy and paste of the controls into a new form and gradually add back in the code.
I have had that happen to me many times. Here are a couple things that have saved my bacon. I am assuming you are using Access 2003 or higher. Try converting the database to Access 2002 or 2000 format. Then convert that database back to your current version.
Here is some code that I created to combat bloat in previous versions. It also solved this issue for me 95% of the time.
Option Compare Database
Option Explicit
Private Sub cmdCreateDuplicate_Click()
'********************************************************
' Author Daniel Tweddell
' Revision Date 10/27/05
'
' To Combat bloat, we are recreating the a new database
'********************************************************
On Error GoTo Err_Function
Dim strNewdb As String
Dim AppNewDb As New Access.Application 'the new database we're creating to manage the updates
strNewdb = CurrentProject.Path & "\db1.mdb"
SysCmd acSysCmdSetStatus, "Creating Database. . ."
With AppNewDb
DeleteFile strNewdb 'make sure it's not already there
.Visible = False 'hear no database see no database
.NewCurrentDatabase strNewdb 'open it
ChangeRemoteProperty "StartupShowDbWindow", AppNewDb, , dbBoolean, False
ChangeRemoteProperty "Auto compact", AppNewDb, , dbBoolean, True
ImportReferences AppNewDb, Application
.CloseCurrentDatabase
End With
Set AppNewDb = Nothing
Dim ao As AccessObject
For Each ao In CurrentData.AllTables
If Left(ao.Name, 4) <> "msys" Then
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acTable, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
End If
Next
For Each ao In CurrentData.AllQueries
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acQuery, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
For Each ao In CurrentProject.AllForms
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acForm, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
For Each ao In CurrentProject.AllReports
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acReport, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
For Each ao In CurrentProject.AllMacros
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acMacro, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
For Each ao In CurrentProject.AllModules
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acModule, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
MsgBox "Creation Complete!" & vbCrLf & "Reset Password", vbExclamation, "New Database"
Exit Sub
Err_Function:
ErrHandler Err.Number, Err.Description, Me.Name & " cmdCreateDuplicate_Click()"
End Sub
Function DeleteFile(ByVal strPathAndFile As String) As Boolean
'***********************************************************************************
' Author Daniel Tweddell
' Revision Date 04/14/03
'
' Deletes a file
'***********************************************************************************
On Error GoTo Err_Function
DeleteFile = True 'default to true
If UncDir(strPathAndFile) <> "" Then 'make sure the file is there
Kill strPathAndFile 'delete a file
End If
Exit Function
Err_Function:
ErrHandler Err.Number, Err.Description, "DeleteFile()", bSilent
DeleteFile = False 'if there is a problem, false
End Function
Public Sub ChangeRemoteProperty(strPropName As String, _
appToDB As Access.Application, Optional appFromDB As Access.Application, _
Optional vPropType As Variant, Optional vPropValue As Variant)
'********************************************************************************
' Author Daniel Tweddell
' Revision Date 01/13/04
'
' Changes/adds a database property in one db to match another
'********************************************************************************
On Error GoTo Err_Function
Dim ToDB As DAO.Database
Dim FromDB As DAO.Database
Dim prpTest As DAO.Property
Dim bPropertyExists As Boolean
Set ToDB = appToDB.CurrentDb
If Not appFromDB Is Nothing Then Set FromDB = appFromDB.CurrentDb
bPropertyExists = False 'flag to see if we found the property
For Each prpTest In ToDB.Properties 'first see if the property exists so we don't error
If prpTest.Name = strPropName Then
If IsMissing(vPropValue) Then vPropValue = FromDB.Properties(strPropName) 'in case we want to assign it a specific value
ToDB.Properties(strPropName) = vPropValue 'if it does set it and get out or the loop
bPropertyExists = True
Exit For
End If
Next
If Not bPropertyExists Then ' Property not found.
Dim prpChange As DAO.Property
If IsMissing(vPropValue) Then
With FromDB.Properties(strPropName)
vPropValue = .Value 'in case we want to assign it a specific value
vPropType = .Type
End With
End If
Set prpChange = ToDB.CreateProperty(strPropName, vPropType, vPropValue) 'add it
ToDB.Properties.Append prpChange
End If
Exit Sub
Err_Function:
ErrHandler Err.Number, Err.Description, "ChangeRemoteProperty()", bSilent
End Sub
Public Sub ImportReferences(AppNewDb As Access.Application, appUpdateDB As Access.Application, Optional iStatus As Integer)
'********************************************************************************
' Author Daniel Tweddell
' Revision Date 01/13/04
'
' Copies the current references from the one database to another we're building
'********************************************************************************
On Error GoTo Err_Function
Dim rNewRef As Reference
Dim rUpdateRef As Reference
Dim bReferenceExists As Boolean
Dim rToAdd As Reference
Dim sReference As String
If iStatus <> 0 Then ProgressBarUpdate iStatus, "Referencing Visual Basic Libraries. . ."
For Each rUpdateRef In appUpdateDB.References
bReferenceExists = False
For Each rNewRef In AppNewDb.References
sReference = rNewRef.Name
If rUpdateRef.Name = sReference Then
bReferenceExists = True
Exit For
End If
Next
If Not bReferenceExists Then
With rUpdateRef
Set rToAdd = AppNewDb.References.AddFromGuid(.Guid, .Major, .Minor)
End With
End If
Next
Exit Sub
Err_Function:
ErrHandler Err.Number, Err.Description, "ImportReferences(" & sReference & ")", bSilent
Resume Next
End Sub
I have found that combo boxes with 10 or more columns can cause an Access form to corrupt. Try reducing the number of the columns or removing that combo box to see if the form saves properly. This problem is was related to working in Win 7 64 bit operating system with Access 2003 databases. There was no problem when developing in XP in other words the forms save fine with large column counts in combo boxes. Hope this information helps since it caused a lot of wasted time thinking the database was corrupted.

MS Access search for record by textbox instead of dropdown

I'm pretty new to MS Access. I'm trying to create a simple form that will basically search for a particular record using a textbox, rather than a drop down box. Essentially a user would be able to enter an ID number and retrieve some other related Info. However, I do not want the user to be able to add any new records to the database. I've been able to get the forms to look the way I want them, but I'm not sure where to place the code (do I create a macro, insert the code into the properties of the button?) Any help is greatly appreciated!
I assume that you have bound your form to a table or a query and that you want to be able to enter the ID manually in a textbox, then press ENTER and load that record's data or display an error message if there is no such record.
As dsteele said, make sure that the form's Data property Allow Addtions is set to No to disallow users from adding records.
Then, from the AfterUpdate event of the textbox, add the following code (assuming that your textbox is named txtGoTo):
Private Sub txtGoTo_AfterUpdate()
If (txtGoTo & vbNullString) = vbNullString Then Exit Sub
Dim rs As DAO.RecordSet
Set rs = Me.RecordsetClone
rs.FindFirst "[ID]=" & txtGoTo
If rs.NoMatch Then
MsgBox "Sorry, no such record '" & txtGoTo & "' was found.", _
vbOKOnly + vbInformation
Else
Me.RecordSet.Bookmark = rs.Bookmark
End If
rs.Close
txtGoTo = Null
End Sub
Note that you will have to change the line rs.FindFirst "[ID]=" & txtGoTo to something that is adequate for your data:
"[ID]=" should be replaced by the field you want to search (it could be "[POReference]=" or something else.
if you are searching by a numeric ID, for instance because the field is an autonumber column, then the code is fine.
Otherwise, if the field you are searching on is a string (say PN12-G) then you have to change the code to:
rs.FindFirst "[ID]=""" & txtGoTo & """"
Failing to use the proper quoting (or quoting where not necessary) will result in errors of the kind Data type mismatch....
As a new user, I would recommend that you have a look at the sample NorthWind project database that is either shiped with older versions of Access or available as a template for download from Access 2007.
There a lots of techniques to learn from as a new Access developer, including other ways to implement record navigation.
Set the form property Data/'Allow Additions' to No.
Either in the AfterUpdate event of the textbox, or in the Click event of a button, you can write code or assign a macro to look up and display the record you want.