Skipping files in a directory with same name from inputbox - excel

I am creating a code that opens and imports data from a file that is selected based on a client's name. Each time a client is opened, a file is saved for them with their name and date of birth (without slashes).
A sample file would look like C:\Data\Clients\John Doe 01011900.xlsx. An InputBox on button-click provides a client's name, but what I'm getting stuck on is if there are 2 or more John Does in the folder.
Check = Application.InputBox(prompt:="What is your client's first and last name?", Type:=2)
FilePath = "C:\Data\Clients\" & Check & "*.xlsx"
If Dir(FilePath, vbDirectory) = "" Then
Exit Sub
End If
DOB = MsgBox("Is this your client's date of birth? " & " " & Chr(149) & " " & Mid(Dir(FilePath), Len(Dir(FilePath)) - 12, 2) & "/" & Mid(Dir(FilePath), Len(Dir(FilePath) - 10, 2) & "/" & Mid(Dir(FilePath), Len(Dir(FilePath) - 8, 4) & " " & Chr(149), vbYesNoCancel)
If DOB = vbYes Then
Workbooks.Open (FilePath)
'Transfer Data
ActiveWorkbook.Close False
ElseIf DOB = vbNo Then
'Try again.
ElseIf DOB = vbCancel Then
'Do nothing.
End If
My confusion is occurring at the DOB = vbNo, when someone says the date of birth does not match (meaning the next client with the same name needs to be selected). Everything else works great so far, so I just need help with the re-selection of the next file with the same name.

You can loop through all the matches by adding a strDir = Dir at the end of your loop, which will exit after the match is met and not accepted (as the length of StrDir will be 0)
update
I realise the code looks a little strange but this is the way Dir works, ie each time it is called it looks for the same match as the initial Dir until it reaches the end of the list. See Loop through files in a folder using VBA?
ie
Do While Len(strDir) > 0
DOB = MsgBox("Is this your client's date of birth?", vbYesNoCancel)
If DOB = vbCancel Then Exit Do
If DOB = vbYes Then
Workbooks.Open (filepath)
ActiveWorkbook.Close False
Exit Do
End If
strDir = Dir
Loop

This is what I would do:
First, use string comparison to find all the files in the directory that starts with John Doe and store them in a dynamic array.
Use For...Each statement to go through the files, and use
Dir(FilePath) LIKE "John Doe*" to find your candidates.
Then use a Do...While loop to go through the files in the array until you find your match.
I could write the entire code for you but then you'd miss all the fun...

Related

How do I add a network path to a name in excel name manager

I have code that works to add a path to a name in the name manager, but only for local paths. When I try to use a network path, the name manager adds a colon before the first single backslash, which keeps the path from working. I have added code to debug, to remove colons, which it seems wasn't necessary. The File open dialog does return the correct path. VBA writes it like this with debug.print:
`="\\win10box3\business\... ..." `
When excel stores it in the name manager it stores it like this
`="\\Win10Box3:\Business\... ..." `
I wrote code to remove the colon before adding the name, but I'm finding the path debug.prints correct before it is stored in the Name Manager, even before the loop to remove the colon.
The only solution I have found is to manually edit the path in the name manager to remove the colon
Sub GetPath()
Debug.Print "Start GetPath routine"
'This sub gets the path to a File defined by the user within the routine
'It then calls another sub that applies that path to a name in the worksheet.
' Before calling this routine, The name should first be searched for, and then verified, then opportunity given to change the name.
Dim MyPath As String 'String to hold the path to an excel spreadsheet exported from quickbooks
Dim NametoChange As String 'String that holds the name manager name to store the path under
Dim NameComment As String 'Comment to identify the name in the name manager
Dim PathLength As Long
Dim PathTemp As String
NametoChange = "PathToEmployeeWithholding"
NameComment = "This Name contains the Path to the 'Employee Withholding' worksheet exported from quickbooks using VBA"
MyMessage = "If you have not already exported and" & vbCrLf & "saved the employee withholding data from Quickbooks," & vbCrLf & "Please choose cancel and export it now"
DoIt = MsgBox(MyMessage, vbOKCancel)
Debug.Print DoIt
If DoIt = vbCancel Then
Exit Sub
End If
With Application.FileDialog(msoFileDialogFilePicker)
If .Show <> 0 Then
MyPath = .SelectedItems(1)
End If
End With
Debug.Print MyPath 'NOTE:This is producing the correct path. It has no colon here...
'Where is the colon coming from?
'IT SEEMS NECESSARY TO REMOVE A COLON IF THE PATH IS A NETWORK PATH
'FIRST VERIFY IT IS NOT A DRIVE PATH... SHOULD BE IN THE FORM OF D:\
'WHAT IS UNIQUE IS THE COLON IS THE 2ND CHARACTER IN THE PATH IF A LOCAL DRIVE.
'TEST TO SEE IF THE INCREMENT IS 2. IF IT IS, SKIP IT, AND REMOVE ALL OTHER COLONS
PathLength = Len(MyPath)
For i = 1 To PathLength
If Not i = 2 Then
If Not Mid(MyPath, i, 1) = ":" Then
PathTemp = PathTemp & Mid(MyPath, i, 1)
End If
Else
PathTemp = PathTemp & Mid(MyPath, i, 1)
End If
Debug.Print "i = " & i & " The current Character is " & _
Mid(MyPath, i, 1) & xlcrlf & "the current PathTemp is " & PathTemp
Next
MyPath = PathTemp
Debug.Print MyPath
Debug.Print "Calling ChangeValueOfName Routine"; vbCrLf & vbCrLf
Call ChangeValueOfName(NametoChange, MyPath, NameComment) 'this routine stores the retrieved text string in the name manager
Debug.Print "Exit GetPath Routine" & vbCrLf & vbCrLf
End Sub
Sub ChangeValueOfName(NametoChange As String, NewNameValue As String, Comment As String)
Debug.Print "Start changeValueOfName routine"
' ChangeValueOfNameManagerName Macro
' Changes the Value of a defined name in the Name Manager
'This should be used to change the name.
'Once the file is selected data needs to be imported to an array, and the
'Employee name values need to be checked against the worksheets in the workbook and against the recap sheet
'If changes are needed, it needs to write them into the workbook, including changing recap sheet and adding
'worksheets for any new employees
With ThisWorkbook.Names(NametoChange)
.Name = NametoChange
.Comment = Comment
RefersToR1C1 = _
"=" & Chr(34) & NewNameValue & Chr(34)
End With
Debug.Print "The New Path added is " & "=" & Chr(34) & NewNameValue & Chr(34)
Debug.Print "Return from ChangeValueOfName routine" & vbCrLf & vbCrLf
End Sub

Pulling file names from SharePoint and saving to SharePoint, using VBA

I'm trying to adapt an Excel form I created that uses drive locations to save copies of the form, to work with SharePoint in a similar manner. Currently, the first macro is set up such that it will search the contents of a particular folder to determine the next available number in the queue (i.e. if 1, 2 and 4 already exist, it will assign 3) and save the sheet as that next available number. When the sheet is complete, the second macro will save the file with a specified name based on data within the sheet, in another specified location (again based on data defined within the sheet). The drive is in the process of being retired in our company and everything moved to Cloud-based storage, so I would like a way to complete the same actions but using SharePoint directories.
The code for the first macro is as follows:
Dim strDir As String
Dim file As Variant
Dim savename As Integer
Dim savename_string As String
strDir = "R:\Queue\"
savename = 1
savename_string = CStr(savename)
file = Dir(strDir)
While (CInt(savename_string) = savename)
If file <> (savename & ".xlsm") Then
If file = "" Then
savename = savename + 1
Else
file = Dir
End If
ElseIf file = (savename & ".xlsm") Then
savename = savename + 1
savename_string = CStr(savename)
file = Dir(strDir)
End If
Wend
ActiveWorkbook.SaveAs ("R:\Queue\" & savename_string & ".xlsm")
And then the code for the second macro is as follows:
Dim answer As Integer
Dim error As Integer
Dim delete As String
answer = MsgBox("Are you sure you want to save sheet & close?", vbYesNo + vbQuestion, "WARNING")
If answer = vbYes Then
'Define PWO, assembly, terminal, strand, and gauge As Strings, and define which cells they are on the sheet
delete = ActiveWorkbook.Name
ActiveWorkbook.SaveAs ("R:\" & terminal & assembly & Space(1) & gauge & strand & Space(1) & PWO & Space(1) & Format(Now(), "MM-DD-YYYY") & ".xlsm")
Kill ("R:\Queue\" & delete)
ActiveWorkbook.Close
Else
Exit Sub
End If
Currently the second macro works correctly when replacing the locations with the SharePoint URL locations, but when doing the same with the first macro, it returns an error message "Bad file name or number" at the line file = Dir(strDir). Can I get this code in working order, or is there a better way I should go about this? Thanks!

Rename opened workbook with incremental number without firstly closing it?

Regarding this question link to rename opened workbook without firstly close it.
The provided answer works greatly ,But I faced cases if new name equal to old name or there is a file with same new name on same folder path.
I modified the code a bit ( as new name will be picked up without user intervention) and added function to check if a file with new name exists or not before rename.
I could not manage to add the incremental number ( added “New” instead).
Now, the code works properly only on first run:
e.g. file name Plan 12-Mar changed to Plan 12-Mar New and Plan 12-Mar deleted , then I closed it.
On second run on the renamed file (Plan 12-Mar New) I got the following message:
file named 'C:\Users\Waleed\Desktop\Plan 12-Mar New.xlsb' already exists in this location. Do you want to replace it?
If I clicked on Yes button , I got this Run-time error '70': Permission denied on this line of code Kill FilePath
Conclusion if I used the code today , if initial name is “Plan 12-Mar” ,then expected actions are (1) save as with rename to “Plan 12-Mar v2” (2) delete the old file “Plan 12-Mar”
and if also I used again today, then expected actions are (1) save as with rename to “Plan 12-Mar v3” (2) delete the old file “Plan 12-Mar v2”.
If I used the code tomorrow, then expected actions are (1) save as with rename to “Plan 13-Mar” (2) delete the old file “Plan 12-Mar v3” , and so on.
Appreciate for yours comments and answers.
Option Explicit
Option Compare Text
Sub Rename_Me()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim DotPosition As Long: DotPosition = InStr(1, wb.Name, ".")
If DotPosition = 0 Then Exit Sub
Dim ibDefault As String: ibDefault = Left(wb.Name, DotPosition - 1)
Dim NewBaseName As String
NewBaseName = "Plan " & Format(Date, "DD-MMM")
If Len(NewBaseName) = 0 Then Exit Sub
Dim FilePath As String: FilePath = wb.FullName
Dim FolderPath As String: FolderPath = wb.path & Application.PathSeparator
Dim Extension As String: Extension = Right(Extension, DotPosition)
Dim ErrNum As Long
On Error Resume Next
If Not Is_File_Exists(wb.FullName) Then
wb.SaveAs FolderPath & NewBaseName & Extension
ErrNum = Err.Number
Else
wb.SaveAs FolderPath & NewBaseName & " New" & Extension 'Instead of "New" ,I v2 ,v3,...
ErrNum = Err.Number
End If
On Error GoTo 0
If ErrNum = 0 Then
Kill FilePath
Else
Kill FilePath
MsgBox "Could not rename.", vbCritical, "Rename Me"
End If
End Sub
And this the function
Function Is_File_Exists(ByVal fName As String) As Boolean
'Returns TRUE if the provided name points to an existing file,
'FALSE if not existing or it's a folder
On Error Resume Next
Is_File_Exists = ((GetAttr(fName) And vbDirectory) <> vbDirectory)
End Function
To allocate a new name, based on the algorithm you try explaining, please use the next function:
Function NewName(strExisting As String) As String
Dim boolToday As Boolean, arrSuffix, arrName, nrSuffix As Long
arrName = Split(strExisting, "."): strExisting = arrName(0)
'check if the root name refers to today date:
If InStr(strExisting, "Plan " & Format(Date, "DD-MMM")) > 0 Then boolToday = True
If boolToday Then
If IsNumeric(Right(strExisting, 1)) Then
arrSuffix = Split(strExisting, " V"): nrSuffix = CLng(arrSuffix(1)) + 1
NewName = arrSuffix(0) & " V" & nrSuffix & "." & arrName(1): Exit Function
Else
NewName = strExisting & " V1." & arrName(1): Exit Function
End If
Else
NewName = "Plan " & Format(Date, "DD-MMM") & "." & arrName(1): Exit Function
End If
End Function
It will add a suffix incrementing the existing number after "V", in case of the name containing current day reference and a new name containing the current date, if a previous one. Then you can delete the workbook with the name sent to the function. It can be tested using the next sub:
Sub testNewName()
Static name As String
If name = "" Then name = "Plan 11-Mar.xlsb"
name = NewName(name): Debug.Print name
End Sub
Run the sub form some times and see the result in Immediate Window.
If, from unknow reasons, a full name identic to the built one can exist, the full name can be checked for its existence and send a message about that before saving As.

Parsing file names to excel vba

I am trying to isolate the address changes I have gotten from a folder containing a series of files with names containing the address changes. See the first image I included as an example of the folder I am drawing from. I iterate through the folder and output the to an excel sheet the original address and the new address to excel. The issue I am encountering is that not all file names are the same so I currently cannot draw the correct address change information from the filenames. The second photo included is a photo of the output, the files in yellow are the filenames that my script cannot iterate for. If anyone has any suggests on how to broaden the number of cases I can deal with it would be very helpful see current code below.
Dim AddChng As Worksheet
If sheetExists("AddressChange") Then 'create a new sheet if one doesn't exist
Set AddChng = ThisWorkbook.Sheets("AddressChange")
Else
Set AddChng = ThisWorkbook.Sheets.Add(After:=Sheets(Sheets.Count))
AddChng.Name = "AddressChange"
End If
AddChng.UsedRange.Delete shift:=xlUp 'clear the sheet
AddChng.Range("A1").Value = "Old Name" 'set up
AddChng.Range("B1").Value = "New Name"
AddChng.Activate
AddChng.Range("A2").Select
Dim StrFile As String
'Change this to the directory containing all Address Change Circulation emails
'This will Pull in a list and, to the best of its ability make two columns that hold the data for
'the old and the new address
StrFile = Dir(Range("AddressChangeFolderPath").Value)
Dim Names() As String
Dim StrName
Do While Len(StrFile) > 0
CheckVal = InStr(1, StrFile, "Address Change Circulation -", vbTextCompare) + _
InStr(1, StrFile, "Address Change Circulation from ", vbTextCompare)
If CheckVal <> 1 Then 'if the email does not fit the standard, just place it in the cell and
'move on to the next entry
Selection.Value = StrFile
Selection.Interior.Color = RGB(255, 255, 0) 'highlight the cell
Selection.Offset(1, 0).Select
Else
StrName = Right(StrFile, Len(StrFile) - 29) 'trim to the correct size - probably not the
'best way to do this but it works
If Left(StrName, 4) = "from" Then
StrName = Right(StrName, Len(StrName) - 5)
ElseIf Left(StrName, 2) = "om" Then
StrName = Right(StrName, Len(StrName) - 3)
End If
StrName = Left(StrName, Len(StrName) - 4)
Changes = Split(StrName, " and ")
For Each Change In Changes
Names = Split(Change, " to ")
If Len(Names(0)) < 5 Then
Selection.Value = Names(0) & Right(Names(1), Len(Names(1)) - Len(Names(0)))
Else
Selection.Value = Names(0)
End If
If UBound(Names) >= 1 Then 'this is a zero indexed array, checking greater than or
'equal to 1 will check if there are two or more entries
Selection.Offset(0, 1).Value = Names(1) ' in the event that there is no " to " in
'the file name and it hasn't been handeled already
End If
Selection.Offset(1, 0).Select 'select the next cell to accept the next entry
Next
End If
StrFile = Dir
Loop
MsgBox "Make sure to QAQC the new table and update any fields that haven't been properly " & _
"filled in by the automation."
End Sub
".. not all file names are the same so .." I would hope so.
You obviously have to add "Address Change from" to the "CheckVal = .." instruction. AND add all other possible variations!
I suggest you check for each individual case individually and handle each case individually. To handle all cases in one "else" has to be wrong. IMHO.

Excel vba Next invoice number with creation of automatic directory folder by month

Ok , here is the thing,
I have created a next invoice number program in which by pressing of a macro assigned button active invoice automatically saved and closed and the next invoice with a number increased appear.My problem is that, I want excel invoices to be created in their relevant folder by their first two digits of invoice number . as an example : 04-001 where 04 stands for April. also, when invoice number is given 05-002, the directory folder of may 2018-19 should be auto created and invoice should be there in the folder only. i am trying to figure out the code since some time but no luck till now. So far , The invoices are created according to date only but as darren said it is a problem for me when i am trying to create invoices from december on first day of january.
This is my current code :
Sub SaveInvoiceM()
Dim NewFN As Variant
If Len(Dir("C:\Invoices\" & Format(Date, "MMM YYYY") & "-" & (Format(Date, "YY") + 1), vbDirectory)) = 0 Then
MkDir "C:\Invoices\" & Format(Date, "MMM YYYY") & "-" & (Format(Date, "YY") + 1)
End If
' Copy Invoice to a New Workbook
NewFN = "C:\Invoices\" & Format(Date, "MMM YYYY") & "-" & (Format(Date, "YY") + 1) & "\Inv" & Range("F5") & ".xlsx"
ActiveWorkbook.saveas NewFN, FileFormat:=xlOpenXMLWorkbook
NextInvoice
End Sub
Range("F5") stands for my invoice number which is 04-001
I see what you are trying to do (keep nicely organized, automatically) and that's an excellent goal.
I have a suggestion of an alternate invoice numbering system (based on what I'm understanding of your situation & experience level) that will make tasks (like this "auto-filing" process) much easier, and will also simplify the process any time you (or especially anyone else) needs to look back at these invoices. There are a number of obvious benefits (same idea as metric vs imperial).
Ideal numbering system: (in my opinion)
To reduce confusion: Give each invoice and filename the same name instead of having a filename with a month and
Since you want granularity from months to years (but not days): make the invoice/file name include the all of those fields.
To make sorting & finding these logical (easier): place each "date part" in order of biggest to smallest. A unique sequential number goes at the very end.
Your code sample was a good start - I just have a bit of OCD when it comes to this kind of thing, and creation of a numbering system is an important task. (Also this will be "date-proof", and error-checked along the way...
This is a little different than what you had because instead of you telling the code what the next invoice number is, it tells you (by figuring out the next number in sequence based on the existing files).
Like yours, it creates a folder if necessary. Since the files are number YYMM-nnn then are always in the correct order when you sort them. (The "month folders" are unnecessary since the month is in the filename, but I included them anyway since that was your plan. You could just keep every month's invoices in one folder, and they'd still be organized in order of month.)
VBA #1: Save file with next sequential invoice number (creating folder if necessary)
Sub createInvoiceNumberAndSave()
'creates a new invoice number based on date in specified cell & creates new folder if necessary
'finds next unused invoice number & verifies that file is properly saved
Const invoicePath = "c:\invoices\" ' invoice root save path
Const fNamePrefix = "Inv" ' prefix for the filename
Const fNameExt = ".xlsm" ' file extension
Const getInvoiceDate = "F5" ' we GET the DATE of the invoice from F5
Const putInvoiceNumber = "F6" ' we will PUT the new filename into cell F6
Dim invDate As Date, folderName As String, fName As String, fNum As Long, nextInvoiceNum As Long
'get the invoice date and make sure it's valid
If IsDate(Range(getInvoiceDate).Value) Then
'valid date found in cell F5
invDate = Range(getInvoiceDate).Value
Else
'valid date not found in F5. Do we want to default to today's date?
If MsgBox("Cell " & getInvoiceDate & " does not contain a valid date." & vbLf & vbLf & _
"Do you want to use today's date instead?", vbQuestion + vbOKCancel, "Date not found") <> vbOK Then
Call MsgBox("Invoice Not Saved.", vbCritical + vbononly, "User Cancelled")
Exit Sub 'stop running
Else
invDate = Date 'use today's date
End If
End If
'find the next unused invoice number for this month
folderName = Format(invDate, "YYMM")
nextInvoiceNum = 0
'figure out the next unused "file number"
fName = Dir(invoicePath & folderName & "\" & fNamePrefix & folderName & "-*" & fNameExt)
If fName = "" Then
'file not found
If Dir(invoicePath & folderName, vbDirectory) = "" Then
'month not found - create folder?
If MsgBox("Okay to create folder '" & invoicePath & folderName & "' for invoice #" & folderName & "-001 ?", _
vbOKCancel + vbQuestion, "Folder not Found") <> vbOK Then Exit Sub
'create folder
MkDir (invoicePath & folderName)
End If
Else
'month found. Now find the highest invoice number in the folder.
Do While fName <> ""
Debug.Print "Found File: " & fName
'get the number (filename = fNamePrefix & "YYMM-___.xlsx" so we know where it is
If IsNumeric(Mid(fName, 6 + Len(fNamePrefix), 3)) Then 'it's a valid number
fNum = Val(Mid(fName, 6 + Len(fNamePrefix), 3))
'if it's the biggest so far, remember it
If fNum > nextInvoiceNum Then nextInvoiceNum = fNum 'biggest one so far
End If
fName = Dir
Loop
End If
'we have the next available invoice#
nextInvoiceNum = nextInvoiceNum + 1 'new invoice# (numeric)
'PUT the new invoice# (text) in cell F6
Range(putInvoiceNumber).Value = fNamePrefix & folderName & "-" & Format(nextInvoiceNum, "000")
fName = invoicePath & folderName & "\" & Range(putInvoiceNumber).Value & fNameExt
Debug.Print "Saving as: " & fName
'save file
ActiveWorkbook.SaveAs fName
'DOUBLE CHECK check that file exists (couple lines of code now save a headache later)
If Dir(fName) = "" Then
'something went wrong (file wasn't saved)
Call MsgBox("ERROR! FILE NOT SAVED: " & fName, vbCritical + vbOKOnly, "ERROR!")
Stop
End If
'success message!
Call MsgBox("Invoice saved successfully:" & vbLf & vbLf & fName, vbInformation, "Invoice Created")
'NextInvoice '?
End Sub
EDIT: ("Back to your way")
I can think of a number of ways that your method will be a problem, some of which I tried explaining, but you're determined to number & organize these files your way, so "here you go".
VBA #2: Save file with cell value as name:
This procedure saves the current file, named from the invoice number (like 04-001) that you enter in cell F5 (creating folder if necessary):
Sub SaveFileBasedOnInvoiceNumber()
Dim monthNum As Long, yearString As String, folderName As String, fName As String
'build filename
On Error Resume Next 'skip errors for now
monthNum = Val(Left(Range("F5"), 2))
yearString = Year(Date) & "-" & Right(Year(Date) + 1, 2)
folderName = "c:\invoices\" & StrConv(monthName(monthNum, True), vbUpperCase) & " " & yearString
fName = folderName & "\INV" & Range("F5") & ".xlsm"
'check if there was a problem
If Err Then MsgBox "Invalid invoice number": Exit Sub
MkDir (folderName) 'create folder
On Error GoTo 0 'turn error checking back on
'Confirm file saved properly
ActiveWorkbook.SaveAs fName 'save file
If Dir(fName) = "" Then MsgBox "Error! File not saved: " & fName: Exit Sub
MsgBox "Invoice saved successfully:" & vbLf & fName
End Sub
I'll leave "VBA #1" in the the top of the answer for others seeking a logical numbering & storage system with auto-generated invoice numbers.
(One day you'll figure out why that way would've been better, but be forewarned, it will be a lot more of a hassle to change your organization method later!)
Good luck!

Resources