User Level permission to different forms - vba

I have code that works for opening one particular form, but I need to setup different user levels which can then be used to restrict access to different forms in the Access program.
I have a login screen which uses data (username/password) from a table employee, this table also has a foreign key column called employeeTypeId, additionally I have a table called Access which has different employeetypeId as 1,2,3,4,5.
5 is supposed to be admin and 1 is read-only user and so on. The third table is EmployeeAccess , it has employeeTypeId as well as column HasAccess with yes/no datatype.
I am using this to write a code in VBA to ensure only certain users have access to certain forms.
I have a code that works for one form, I am trying to figure out how to use this HasAccess column in conjunction with employeeTypeId and different form-names (need to figure out how to use that) to ensure employeetypeId=5 users have access to all forms, employeetypeId=4 has access to lets say all forms except employee table form and employeetypeId=3 has access to edit only a select few forms and so on.
This is the code for accessing the form after login (on load):
Private Sub Form_Load()
If DLookup("HasAccess", "EmployeeAccess", "EmployeeTypeId=" & TempVars("EmployeeType") & " AND FormName='" & Me.Name & "'" = False) Then
MsgBox "Yo do not have access"
DoCmd.Close acForm, Me.Name
End If
End Sub
This is the code in the login form:
Private Sub btnLogin_Click()
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("Employee", dbOpenSnapshot, dbReadOnly)
rs.FindFirst "UserName='" & Me.TextUserName & "'"
If rs.NoMatch = True Then
Me.LabelWrongUser.Visible = True
Me.TextUserName.SetFocus
Exit Sub
End If
Me.LabelWrongUser.Visible = False
If rs!Password <> Encrypt(Me.TextPassword) Then
Me.LabelWrongPass.Visible = True
Me.TextPassword.SetFocus
Exit Sub
End If
Me.LabelWrongPass.Visible = False
TempVars("EmployeeType") = rs!EmployeeTypeId.Value
End Sub
Currently the code opens all the forms when login is correct, I want to change that and give access based on employeeTypeId.
==========================
Private Sub btnLogin_Click()
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("Employee", dbOpenSnapshot, dbReadOnly)
rs.FindFirst "UserName='" & Me.TextUserName & "'"
If rs.NoMatch = True Then
Me.LabelWrongUser.Visible = True
Me.TextUserName.SetFocus
Exit Sub
End If
Me.LabelWrongUser.Visible = False
If rs!Password <> Encrypt(Me.TextPassword) Then
Me.LabelWrongPass.Visible = True
Me.TextPassword.SetFocus
Exit Sub
End If
Me.LabelWrongPass.Visible = False
TempVars("EmployeeType") = rs!EmployeeTypeId.Value
If DLookup("HasAccess", "EmployeeAccess", "EmployeeTypeId=" & TempVars("EmployeeType")) Then
TempVars("FormName") = rs!FormName.Value And DoCmd.OpenForm (
I just want to know how to use the DoCmd.OpenForm with the TempVars("FormName") and if it is possible.

Using the below code I was able to achieve the result:
The Goal was to filter based on EmployeeTypeId and HasAccess set as True (A combination of both to open forms)
TempVars("FormName") = DLookup("FormName", "EmployeeAccess", "EmployeeTypeId=" & TempVars("EmployeeType") & " And HasAccess = " & True & " ")
DoCmd.OpenForm TempVars("FormName")

Related

prevent duplicates when passing values between two forms (with Args)

I have two forms: transfert Form with its subform and intransfert Form. I am using
DoCmd.OpenForm "intransfert", , , , acFormAdd, acDialog, Me!Text83
(where text83 is =[transfertasubform].[Form]![transfertadetailid] under
Private Sub Command78_Click()
in transfet form and
Private Sub Form_Load()
On Error Resume Next
If Me.NewRecord Then Me!trnrin = Me.OpenArgs
in intransfet form. intransfert form is based in transfertdetailquery. i wont to prevent passing text83 value more then one time
i tried to explain my problem and expect a help to prevent duplicates when used Arge
assuming trnrin is the name of a variable in your record source. assuming you mean that you want to avoid adding two records where trnrin has the same value and the user sent the same open args twice. assuming trnrin is also the name of a control in the detail section of the intransfert form.
'form load only runs when the form is opened so you have to close the form to pass new args
'but you can just move the same code to a button or whatever
Private Sub IntransferForm_Load()
If Len(Me.OpenArgs) > 0 Then
Me.txtBoxintheHeader = Me.OpenArgs 'the load event is the right place to set controls
'most of this code is to check if there is already an instance where trnrin = the OpenArgs in the record source
Dim lookedupArgs As String
lookedupArgs = Nz(lookedupArgs = DLookup("trnrin", "MyTable", "trnrin = " & "'" & Me.OpenArgs & "'"), "ValuethatisneveranArg")
If lookedupArgs = "ValuethatisneveranArg" Then
'Debug.Print "trnrin = '" & Me.OpenArgs & "'" 'note the string delimiters
'Me.trnrin = Me.OpenArgs 'this surprisingly works but will break easily and doesn't handle complex cases
Dim rs As Recordset
Set rs = Me.Recordset 'if recordset is bound to a table then table will also be updated.
'you can also bind to the table directly but you may need to call me.requery to show the changes
rs.AddNew
rs!trnrin = Me.OpenArgs
rs.Update
End If
End If
End Sub

VBA code works in one Access Database, but not another. All of the supporting objects have been imported. What I am not seeing?

This code is for a login form I have setup to enter the front end copy of a database. In one database it works like a charm. I imported the form and corresponding objects to another database and it appears to be not recognizing my password when I enter it. I just keep getting the message box I have popping up that says, "Incorrect password". Any help figuring this out would be greatly apprecaited.
The SQL statement that drives the cboUser combo box on the login form is:
SELECT tblUser.UserID, [FName] & " " & [LName] AS Fullname,
tblUser.Password, tblUser.PWReset, tblUser.AccessLevelID
FROM tblUser ORDER BY tblUser.LName, tblUser.FName;
.
Private Sub OkBTN_Click()
Static intIncorrectCount As Integer
Dim AuthorityNumber As Integer
'Dim rs As Recordset
'TempVars("Username") = Me.cboUser.Value
'Column references for cbouser row source reference
'UserID = 0
'FullName = 1
'Password = 2
'PWReset = 3
'AccessLevelID = 4
'Set rs = CurrentDb.OpenRecordset("UserNameQuery", dbOpenSnapshot)
'N = Nz(DLookup("Fullname", "UserNameQuery", "Fullname=""" & Me.cboUser & """"), " ")
'Check that User is selected
If IsNull(Me.cboUser) Then
MsgBox "You forgot To Select your name from the drop down menu!", vbCritical
Me.cboUser.SetFocus
Else
'Check for correct password
If Me.txtPassword = Me.cboUser.Column(2) Then
'Check if password needs to be reset
If Me.cboUser.Column(3) Then
DoCmd.OpenForm "frmPasswordChange", , , "[UserID] = " & Me.cboUser
End If
Me.Visible = FALSE
intIncorrectCount = 0
'Main menu after correct login based on AuthorityNumber
If Me.cboUser.Column(4) = 5 Then
DoCmd.OpenForm "SRL1MainMenu"
'Forms!AMSReportForm!L2Menubtn.Visible = False
Forms!SRL1MainMenu!FullNameLoggedIn = Forms!frmLogin!cboUser.Column(1)
Else
DoCmd.OpenForm "L2MainMenu2"
'Forms!AMSReportForm!L2Menubtn.Visible = True
Forms!L2MainMenu2!FullNameLoggedIn = Forms!frmLogin!cboUser.Column(1)
End If
'Failed login attempt limitation
ElseIf intIncorrectCount > 1 Then
MsgBox "Too many failed login attempts. Click OK To Set New password", vbOK + vbExclamation
DoCmd.OpenForm "frmPasswordChange", , , "[UserID] = " & Me.cboUser
'DoCmd.Close acForm, "frmLogin"
Else
MsgBox "Incorrect password", vbOKOnly + vbExclamation
Me.txtPassword = Null
Me.txtPassword.SetFocus
intIncorrectCount = intIncorrectCount + 1
End If
End If
End Sub
First, #Andre is probably right - you may have to apply brackets to "Password".
Next, this may not perform a case sensitive comparison:
If Me.txtPassword = Me.cboUser.Column(2) Then
Use StrComp to do that:
If StrComp(Me!txtPassword.Value, Me!cboUser.Column(2), vbBinaryCompare) = 0 Then
Finally, you should never store plain passwords; store a hash value instead. It isn't that difficult, if you study my latest article:
Storing passwords in VBA using the Microsoft NG Cryptography (CNG) API

Access modal form updates database then calling form update does not

In Access a header form needs an address associated with it. The header form calls a modal address form. On Save the modal address form will write the address ID to the header form's record source address ID then close. Coming back to the calling header form should then list the related address ID after a requery, that is the FK link. I am not getting the address form's address ID written to the header form's record source address ID field and thus not listing on requery. A fair amount of this code is based on several SO questions.
The header form calls a wrapper function to manage the modal address form:
Private Sub txtJob_AfterUpdate()
gbolDropShipAddressCompleted = False
'Use global variables for use in frmDropShipAddress SQL update statement
gtxtCurrentJobNumber = Me.Job
gtxtCurrentJobRelease = Me.REL
gtxtCurrentJob = Me.txtJob
'Call the wrapper function
gbolDropShipAddressCompleted = fNewDropShipAddressCompletion()
If gbolDropShipAddressCompleted = True Then
'Me.Dirty = False
Me.Requery
With Me.RecordsetClone
.FindFirst "[Job] = '" & gtxtCurrentJobNumber & "' And [REL] = '" & gtxtCurrentJobRelease & "'"
If Not .NoMatch Then
If Me.Dirty Then
Me.Dirty = False
End If
Me.Bookmark = .Bookmark
End If
End With
'Reset all variables
gbolDropShipAddressCompleted = False
gtxtCurrentJobNumber = ""
gtxtCurrentJobRelease = ""
gtxtCurrentJob = ""
End If
End Sub
The wrapper function:
Public Function fNewDropShipAddressCompletion() As Boolean
'Manages call to frmDropShipAddress
DoCmd.OpenForm "frmDropShipAddress", , , , , acDialog, "From frmPackingSlipHeader"
fNewDropShipAddressCompletion = gbolfrmDropShipAddressTofrmPackingSlipHeader
DoCmd.Close acForm, "frmDropShipAddress"
End Function
The modal form's two events:
Private Sub btnSaveAddressInfo_Click()
DoCmd.RefreshRecord
'Update MAIN table with new address id using global variables
CurrentDb.Execute " UPDATE [MAIN] " & _
" SET intADDRESS_ID = " & Me.txtAddress_ID & _
" WHERE JOB = '" & gtxtCurrentJobNumber & "'" & _
" AND REL = '" & gtxtCurrentJobRelease & "'"
gbolfrmDropShipAddressTofrmPackingSlipHeader = True
Me.Visible = False
End Sub
Private Sub Form_Open(Cancel As Integer)
gbolfrmDropShipAddressTofrmPackingSlipHeader = 0
If Me.OpenArgs = "From frmPackingSlipHeader" Then
DoCmd.GoToRecord , , acNewRec
'Coded because TabCtlDatePicker opens all forms and openargs is NULL and causes all forms to be affected
ElseIf IsNull(Me.OpenArgs) Then
Exit Sub
' Else
' Me.PopUp = True
' Me.Modal = True
' Me.BorderStyle = 1
' Me.NavigationButtons = False
' Me.RecordSelectors = False
End If
End Sub
The Access front-end uses several tab controls to select between many different reports/date and or data pickers all sorted into tab control pages by topic. The back-end is MS SQL server via linked tables. The address form may be opened for generic viewing or called (modal). I can't seem to get the correct VBA to get the address form's address ID written to the header's record source and the VBA to get the header to requery and return to the correct record. Any help would be appreciated and TIA.
Tim

Filtering data on form causes combo box to not function

I have a form that displays student records.
I have a combobox that allows you to select a student.
Finally, I have two buttons for filtering. One filters on all Students the other only active Students.
Two Issues which I beleive are related.
One, when the form loads the cbo does NOT work.
Two, if I select the "All Students" button the cbo works. When I select the "Active Students" button the cbo does NOT work again.
Form Record Source:
Select tblStudents.*
Form Load:
Private Sub cmdStudent_Click()
On Error GoTo cmdStudent_Click_Err
DoCmd.OpenForm "frmStudents", acNormal, "", "[Last3]=" & "'" & "Sanders
862" & "'", , acNormal
cmdStudent_Click_Exit:
Exit Sub
cmdStudent_Click_Err:
MsgBox Error$
Resume cmdStudent_Click_Exit
End Sub
ComboBox Code:
Private Sub cboFindRecord_AfterUpdate()
' Find the record that matches the control.
Dim rs As Recordset
Set rs = Me.RecordsetClone
rs.FindFirst "[SN] = '" & Me![cboFindRecord] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
End Sub
All Students Button:
Private Sub cmdAllStudents_Click()
cmdAllStudents.ForeColor = 16777215
cmdAllStudents.BackColor = 16711680
cmdAllStudents.FontBold = True
cmdActiveStudents.ForeColor = 0
cmdActiveStudents.BackColor = 16777215
cmdActiveStudents.FontBold = False
Me.FilterOn = False
cboFindRecord.RowSourceType = "Table/Query"
cboFindRecord.RowSource = "SELECT tblStudents.SN, tblStudents.Last3 FROM
tblStudents ORDER BY tblStudents.Last3;"
cboFindRecord.Requery
Call cboFindRecord_AfterUpdate
cboFindRecord.SetFocus
End Sub
Active Student Button:
Private Sub cmdActiveStudents_Click()
cmdActiveStudents.ForeColor = 16777215
cmdActiveStudents.BackColor = 16711680
cmdActiveStudents.FontBold = True
cmdAllStudents.ForeColor = 0
cmdAllStudents.BackColor = 16777215
cmdAllStudents.FontBold = False
Me.FilterOn = True
cboFindRecord.RowSourceType = "Table/Query"
cboFindRecord.RowSource = "SELECT tblStudents.SN, tblStudents.Last3,
tblStudents.Status_ID FROM tblStudents WHERE (((tblStudents.Status_ID) Not
In (6,7))) ORDER BY tblStudents.Last3;"
cboFindRecord.Requery
Call cboFindRecord_AfterUpdate
cboFindRecord.SetFocus
End Sub
Thank you for any assistance.
I have tried modifying the record set to match all or active students with no change.
OK, not sure why this is happening but I have fixed my issue. The problem is with the form loading code.
When I was loading the Student from from another form, I had it load our test student by default. My theory is that this was changing the record-set. I would appreciate an explanation if someone knows.
I removed forcing the student record when loading the student form and put the code in the On Load event for the form.

Me.Dirty moves currently selected record

I have an Access 2007 form that's giving me some headache.
I have a list of records that start as a combo box to pick a company and then a series of checkboxes to indicate the company's role.
If the user needs to add a new company, they'd pick the company name from the combo box, and then click the checkbox that indicates what role the company is playing. When the checkbox is checked, the form follows the following code to show a popup that captures additional information:
Private Sub chkOperationsAndMaintenance_AfterUpdate()
'DoCmd.RunCommand acCmdSaveRecord'
If Me.Dirty Then Me.Dirty = False
If chkOperationsAndMaintenance.Value = True Then
DoCmd.OpenForm "OmPopupForm", , , "CompanyProjectId = " & Me.CompanyProjectID, , acDialog
Me.Requery
End If
End Sub
This code will save the record on the CompanyProject table to create the row. It then pulls the CompanyProjectID (PK of the CompanyProject table) so it knows which ID to feed the popup.
The issue I'm having is that on the Me.Dirty line (and also the above commented-out acCmdSaveRecord), the entire form saves and refreshes, moving the selected row to the first record (in this case, "Gamesa") rather than the newly entered record. So the ensuing popup is fed the CompanyProjectID of the first record rather than the newly-entered record, and it also reads the "checked" state of the checkbox from the first record rather than the one upon which the user is working.
I doctored the code to look like this:
Private Sub chkOperationsAndMaintenance_AfterUpdate()
Dim CPID As Long
Dim CID As Long
Dim rs As Recordset
Set rs = Me.RecordsetClone
CID = Me.CompanyID
'DoCmd.RunCommand acCmdSaveRecord'
If Me.Dirty Then Me.Dirty = False
CPID = DLookup("MAX(CompanyProjectID)", "CompanyProject", "cpProjectID = " & Me.cpProjectID & _
" AND CompanyID = " & CID)
rs.Find "[CompanyProjectID] = " & CPID
Me.Bookmark = rs.Bookmark
If chkOperationsAndMaintenance.Value = True Then
DoCmd.OpenForm "OmPopupForm", , , "CompanyProjectId = " & Me.CompanyProjectID, , acDialog
Me.Requery
End If
End Sub
The idea with these alterations is that we'll get the FK from the parent form ("cpProjectID") and the CompanyID of the selection from the combobox, then save the record. Once the record is saved, we have the CompanyProjectID already stored, so then the rs.Find and Me.Bookmark lines will then select the record that matches that CompanyProjectID.
This sometimes works, and sometimes doesn't. Generally doesn't. In this case, I refreshed the parent form and the current form and attempted to add a new company and then click the "Owner" checkbox (which uses the same code as above, just a different checkbox ID) to see the Bookmark on the wrong row:
At this point, I'm not sure what to do. If I don't save the record (via acCmdSaveRecord or Me.Dirty=False) then I don't have a CompanyProjectID to send as the input parameter for the ensuing popup, but if I do save the record, then the form changes the record and the wrong parameter is sent and the wrong checkbox's checked state is read. I can't just use an arbitrary index to work off of (such as acNewRec), as the user might need to edit an existing row instead of adding a new one.
I tried the method in this post already: MS Access how to Update current row, move to next record, not first, but the find/bookmark isn't consistently working.
EDIT (12/15/2014)
I ended up going with the following VBA code:
Private Sub chkOperationsAndMaintenance_AfterUpdate()
Dim CPID As Long
Dim CID As Long
Dim rs As Recordset
Set rs = Me.RecordsetClone
CID = Me.CompanyID
If Me.Dirty Then Me.Dirty = False
CPID = DLookup("MAX(CompanyProjectID)", "CompanyProject", "cpProjectID = " & Me.cpProjectID & _
" AND CompanyID = " & CID)
Do While Me.CompanyProjectID <> CPID
If Me.CurrentRecord < Me.Recordset.RecordCount Then
DoCmd.GoToRecord , , acNext
Else
DoCmd.GoToRecord , , acFirst
End If
Loop
If chkOperationsAndMaintenance.Value = True Then
DoCmd.OpenForm "OmPopupForm", , , "CompanyProjectId = " & Me.CompanyProjectID, , acDialog
Me.Requery
End If
End Sub
I feel like there has to be a better answer for this, but this is appearing to work right now. I have my end user/lab rat testing it at the moment, so I'll mark this complete if this pans out. I still think there has to be a better solution for this, but at the moment, this solution is able to capture the requisite ID to pass to the popup, and it selects the appropriate row after this ID is captured.
Have you considered saving the current position - like Me.CurrentRecord, then after the save reposition to the desired record. As an example, you could add a 'Before' or 'After' Insert to save the position, then later reposition. See the following:
Option Compare Database
Option Explicit
Dim lCurRec As Long
Private Sub Form_AfterInsert()
lCurRec = Me.CurrentRecord
Debug.Print "After Insert, Current: " & Me.CurrentRecord
End Sub
<<< YOUR SUB>>>
DoCmd.GoToRecord acDataForm, Me.Name, acGoTo, lCurRec
This code will work when adding a new record as well as when editing an existing record:
Private Sub chkOperationsAndMaintenance_AfterUpdate()
Dim c As Long
Me.Dirty = False
If chkOperationsAndMaintenance Then
DoCmd.OpenForm "OmPopupForm", , , "CompanyProjectId = " & Me.CompanyProjectID, , acDialog
c = Me.CurrentRecord
Me.Requery
DoCmd.GoToRecord , , acGoTo, c
End If
End Sub
I am guessing that your popup form does things that are specific to Operations & Maintenance, and does not change the values of any of the checkboxes on the main form. If this is the case, you don't need a Requery at all, and the code can be simplified:
Private Sub chkOperationsAndMaintenance_AfterUpdate()
Me.Dirty = False
If chkOperationsAndMaintenance Then
DoCmd.OpenForm "OmPopupForm", , , "CompanyProjectId = " & Me.CompanyProjectID, , acDialog
End If
End Sub