Save & close workbook with current date as name - vba

I am quite new in VBA and I’m looking to automate a current process using VBA.
For every week of each month (Wednesday), I need to export an existing Excel template from Internet into a new workbook. This part is done but i would need to :
Save it like: "01 05 2018_With taxes_1889". I have so far found and adapted the code below which, when run once, creates a temporary file and save it into my folder but do not closed it automatically.
It would be great to have all download file saved with their related date in my folder.
I’m also willing to completely automate the process with a query which will launch the process each Wednesday of each week?
Private Sub ADD_BTN_Click()
Dim line As Integer
Dim Ws As Worksheet
Dim DBS As Database
Dim RST As Recordset
Dim SQL_TXT As String
Dim COUNTRY_ID As Integer
Dim DATE_FUEL As String
Dim test As Boolean
DownloadFile (LINK_FUEL) ' Download file on C:\TEMP
Workbooks.Open (BUFFER_FILE)
Set Ws = ActiveWorkbook.Worksheets("Weekly Prices with taxes")
datEfuel = Right(Ws.Cells(1, 12), 10)
For line = 1 To 47
If OPEN_DBS(DBS, FUEL_DB) Then
SQL_TXT = "SELECT * FROM COUNTRY_DATA WHERE COUNTRY_NAME LIKE '" & Ws.Cells(line, 1).Value & "'" ' Search Country name
If OPEN_RST(DBS, RST, SQL_TXT) Then
COUNTRY_ID = RST![COUNTRY_ID]
RST.Close
SQL_TXT = "SELECT * FROM FUEL_DATA WHERE COUNTRY_ID=" & COUNTRY_ID
test = True
If OPEN_RST(DBS, RST, SQL_TXT) Then
While Not RST.EOF
If RST![FUELDATA_DATE] = CDate(datEfuel) Then test = False
RST.MoveNext
Wend
RST.Close
End If
If test Then
SQL_TXT = "SELECT * FROM FUEL_DATA"
OPEN_NEW DBS, RST, SQL_TXT
RST![COUNTRY_ID] = COUNTRY_ID
RST![FUELDATA_DATE] = datEfuel
RST![FUELDATA_AUTOMOTIVE] = Ws.Cells(line, 8).Value
RST.Update
End If
End If
DBS.Close
End If
Next line
End Sub

In order to close and save the workbook with a specified name, you can call the Close method on the Workbook object, with True as the first parameter to save changes, and the name under which you want to save the file as the second parameter:
Dim book As Workbook
...
book.Close True, "01 05 2018_With taxes_1889.xlsx"
The Workbook object is returned from the Workbooks.Open method:
'Instead of this:
' Workbooks.Open (BUFFER_FILE)
'use this:
Set book = Workbooks.Open (BUFFER_FILE)
If you want to use the current date as the name of the file, you can use the Date function:
book.Close True, Date & ".xlsx"
You may want to use a specific format for the date in the name; this can be done with the FormatDate function, which formats a date using a predefined set of date formats:
'Uses the long date format from the computer's regional settings
book.Close True, FormatDate(Date, vbLongDate) & ".xlsx"
or with the Format function, which allows for custom formatting:
book.Close True, Format(Date, "yyyy-mm-dd") & ".xlsx"
Note that this will save in the current folder of the application (usually the Documents folder), unless you specify the full path.
book.Close True, "C:\path\to\folder\" & Format(Date, "yyyy-mm-dd") & ".xlsx"
Excel doesn't provide facilities for scheduled tasks, which means you'll have to do one of the following:
use the Windows Task Scheduler to start the task. In that case I would strongly suggest not tying the code to a specific workbook, but rather using VBScript under Windows Script Host.
check each time the workbook (or whereever this VBA code is running from) is opened, and run the process under the appropriate conditions

Related

Open the same workbook but different path every week

I would like to open a file that is located in a different folder every week (file name remains the same but new week = new data).
Workbooks.Open "C:\Users\baguette\Documents\W44\L060.xlsx"
The week folder is obviously W44. Is there a way I could use a cell content that would be taken into account in the code?
For example, cell A1 of sheet1 of the file the code is run from would contain the week number that I would manually key in before running the procedure.
I tried this but did not work :
Workbooks.Open "C:\Users\baguette\Documents\& ThisWorkbook.Worksheets(1).Range("A1")\L060.xlsx"
I guess it was a bit rash.
Thank you for your help.
You are very close to your solution. Just try below-
Workbooks.Open "C:\Users\baguette\Documents\" & _
ThisWorkbook.Worksheets(1).Range("A1") & _
"\L060.xlsx"
You can decorate code using string type variable. Check below sub.
Sub OpenSpecificFile()
Dim FolderPath As String
Dim WeekFolder As String
FolderPath = "C:\Users\baguette\Documents\"
WeekFolder = ThisWorkbook.Worksheets(1).Range("A1")
Workbooks.Open (FolderPath & WeekFolder & "\L060.xlsx")
End Sub

Using Workbook.Sheets.Range to reference file path in Excel

First, is what I'm doing here logical?
Second, I keep getting an error on my single quote that begins my filepath.
stuff = Workbooks('\\public\Documents\Amazon Retail\Analysis\[US Retail Quick Reference.xlsx]').Sheets("Quick Reference").Range("A1")
Assuming you have a single instance of Excel, and are not using multiple instances of Excel:
If that file is already open, you have to reference it by its name only, not the full path. If the file isn't yet open, you need to open it first (and then refer to it by its name only).
Change this:
stuff = Workbooks('\\public\Documents\Amazon Retail\Analysis\[US Retail Quick Reference.xlsx]').Sheets("Quick Reference").Range("A1")
To This:
stuff = Workbooks("US Retail Quick Reference.xlsx").Sheets("Quick Reference").Range("A1")
Ensure stuff is declared as a String or possibly as a Variant type (in case A1 might contain non-text or error values).
If you don't know at runtime whether the file is or may be open, then you can fancify your code like so:
Function IsWorkbookOpen(path as String, name as String) As Boolean
Dim wb as Workbook
On Error Resume Next
Set wb = Workbooks(name)
If wb.FullName = path & name Then
IsWorkbookOpen = True
End If
End Function
And then do like:
Dim path as String, fileName as String
path = "\\public\Documents\Amazon Retail\Analysis\"
fileName = "US Retail Quick Reference.xlsx"
If (IsWorkbookOpen(path & fileName)) Then
stuff = Workbooks(fileName).Sheets("Quick Reference").Range("A1").Value
Else
' Do Something Else // UNTESTED:
stuff = ExecuteExcel4Macro("'" & path & "[" & fileName & "]" & _
"Quick Reference'!" & Range("A1").Address(True, True, -4150))
' or:
' Dim wb as Workbook
' Set wb = Workbooks.Open(path + fileName)
' stuff = wb.Sheets("Quick Reference").Range("A1").Value
' wb.Close
End If
For the "Something Else", I'd recommend using the ExecuteExcel4Macro method for obtaining value from a closed workbook.

How to properly from VBA connection from Excel sheet to another Excel sheet?

I currently have 2 separate Excel worksheets. One is data entry and another is display.
The display uses VBA to connect to data entry to obtain data. Normally, it functions well enough. However I'm required to have the 2 worksheets in separate windows, meaning both can be displayed at the same time in separate windows, in the same screen.
The issue in this scenario is that when I click Execute in display to begin SQL query, the display window opens another data entry worksheet (read-only) and reads that instead of the one I opened initially. Is this issue due to my connection string or my ADODB.Recordset has issues?
Here is the sub which contains the connection string and ADODB.Recordset.
Edit: Full code is included to provide full context for those who need it.
Public Sub QueryWorksheet(szSQL As String, rgStart As Range, wbWorkBook As String, AB As String)
Dim rsData As ADODB.Recordset
Dim szConnect As String
On Error GoTo ErrHandler
If AB = "1st" Then
wbWorkBook = ThisWorkbook.Sheets("Inner Workings").Range("B9").Text
End If
Application.StatusBar = "Retrieving data ....."
'Set up the connection string to excel - thisworkbook
szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & wbWorkBook & ";" & _
"Extended Properties=Excel 8.0;"
Set rsData = New ADODB.Recordset
'Run the query as adCmdText
rsData.Open szSQL, szConnect, adOpenForwardOnly, adLockReadOnly, adCmdText
'Check if data is returned
If Not rsData.EOF Then
'if the recordset contains data put them on the worksheet
rgStart.CopyFromRecordset rsData
Else
End If
'Close connection
rsData.Close
'Clean up and get out
Set rsData = Nothing
Application.StatusBar = False
Exit Sub
ErrHandler:
'an error occured in the SQL-statement
MsgBox "Your query could not be executed, the SQL-statement is incorrect."
Set rsData = Nothing
Application.StatusBar = False
End Sub
Sub process()
Call clear
Call testsql("1st") ' populate 1st Summary
Call testsql("2nd") ' find Date+Time
Call testsql("3rd") ' arrange record by newest
Call testsql("4th") ' show final results
End Sub
Sub testsql(AB As String)
Dim rgPlaceOutput As Range 'first cell for the output of the query
Dim stSQLstring As String 'text of the cell containing the SQL statement
Dim rg As String, SQL As String
If AB = "1st" Then
stSQLstring = ThisWorkbook.Sheets("Inner Workings").Range("B2").Text
Set rgPlaceOutput = ThisWorkbook.Sheets("1st Summary").Range("A2")
End If
If AB = "2nd" Then
stSQLstring = ThisWorkbook.Sheets("Inner Workings").Range("B3").Text
Set rgPlaceOutput = ThisWorkbook.Sheets("2nd Summary").Range("A2")
End If
If AB = "3rd" Then
stSQLstring = ThisWorkbook.Sheets("Inner Workings").Range("B4").Text
Set rgPlaceOutput = ThisWorkbook.Sheets("3rd Summary").Range("A2")
End If
If AB = "4th" Then
stSQLstring = ThisWorkbook.Sheets("Inner Workings").Range("B5").Text
Set rgPlaceOutput = ThisWorkbook.Sheets("Final Summary").Range("A5")
End If
QueryWorksheet stSQLstring, rgPlaceOutput, ThisWorkbook.FullName, AB
End Sub
Sub clear()
ActiveWorkbook.Sheets("1st Summary").Range("A2:BR5000").Value = Empty
ActiveWorkbook.Sheets("2nd Summary").Range("A2:BR5000").Value = Empty
ActiveWorkbook.Sheets("3rd Summary").Range("A2:BR5000").Value = Empty
ActiveWorkbook.Sheets("Final Summary").Range("A5:BR5000").Value = Empty
End Sub
Also another thing I noticed. Depending on which file I open first, it can result in both files creating a read-only copy when I click Execute. If I open Display first then Entry form, both in different instances of Excel, it will create read-only copies of both files.
If I open Entry form first, then Display in again, different instances of Excel, only the read-only copy of Display will appear.
The only time a read-only does not appear is when both files are in a single instance of Excel, which is not what I want.
Edit2:
For more info, here is the SQL I used (4 total)
SQL1 - select * from EntryTable
SQL2 - select A.*,[Date + Time] from Summary1 A left join (select [Die No], max (Date + Time) as [Date + Time] from Summary1 group by [Die No]) B on A.[Die No] = B.[Die No]
SQL3 - select * from Summary2 where [Date + Time] = Date + Time
SQL4 - select Project_No, Die_No, Description, Repair_Details, Status from Summary3
Workbook name in cell B9 = V:\Die Maintenance System v2\Die Maintenance Menu.xlsx
Update: My colleague has tested the system on her PC and tested no problems. I've been told its most likely my Excel settings. But for the life of me, I can't figure out what is causing it. What type of setting is used to prevent the read-only file from appearing?
Edit: I can see that this post has gone on too long. I decided to continue this on a new thread right here.
So i would do it with the Workbook.Open() Method.
Sub Example()
Dim wb as Workbook
Dim path as String
path = "C:\Users\User\Desktop\1.xlsx"
set wb = Workbook.Open(path)
End Sub
Now you can use wb to execute every vba function. Then there a options to check if a workbook is already opened, look here. I dont think you can do that with adodb.
I tired using ACE and it worked just fine. It didn't open a new file.
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & _
wbWorkBook & "';" & _
"Extended Properties='Excel 12.0;HDR=Yes;IMEX=1';"
Your SQL FROM clause is referencing a different named range. Please post your SQL text. It must be qualified to correct Named Range or sheet name.
SELECT Project No, Die No, Description, Repair Details, Status
FROM DATA1 <- correct this to qualified named range or sheet name
like
FROM [Entry Form$] 'or
FROM [Named Range] <- this can be found in Formulas | Name Manager
Edit:
I am not sure about your "1st" source workbook's location so let us try to insert the line I commented below
wbWorkBook = ThisWorkbook.Sheets("Inner Workings").Range("B9").Text
wbWorkBook = Workbooks(wbWorkbook).FullName '<- add this line
If it still does not work, please post your SQL AND Workbook name in cell B9.
Edit 2:
What is the result if you change the FROM clause like:
select * from [EntryTable$]
Edit 3: Do you have password? if so, try to disable it first to isolate the problem in read only.

Receive notification of file creation in VBA without polling

I am writing a program that integrates with a ScanSnap scanner. ScanSnap scanners do not support TWAIN. Once a document is scanned it is automatically saved to a PDF.
I want to monitor the directory where the files will be saved and take some action when the file appears (and is done being written to). A simple approach is to use the MS Access form Timer event and check for an existing file at some small interval of time.
Is there a better alternative via Windows Messaging, the FileSystemObject, or some Windows API function that supports callbacks?
This provides a native WinAP + VB/VBA way of doing the job, I expect:
http://books.google.com/books?id=46toCUvklIQC&pg=PA757&lpg=PA757&dq=windows+api+monitor+directory+changes+vba&source=bl&ots=jmMY4sJFK4&sig=KCB6B_soEA9_JzjlhyNZvSC91w4&hl=en&sa=X&ei=cUAMUsDzOe3iyAHu8YGwAg&ved=0CFIQ6AEwBw#v=onepage&q=windows%20api%20monitor%20directory%20changes%20vba&f=false
Nothing inside Excel.
You can create another application that monitors the file system, and executes the Excel macro, opening the workbook if required, opening Excel if required.
#Steve effectively answered the question I asked. What I should have asked is how to monitor file system changes in a thread separate from the MS Access UI thread. And the simple answer to that question is that VBA does not support multi-threading in Office applications.
There are a variety of workarounds that generally involve calling an external COM library or integrating with an external application. I decided none of those was very appealing and instead decided to implement the solution in VB.Net using the FileSystemWatcher class.
Not sure if this really solves your Problem, but here is an approach using Excel VBA that helped me monitor a specific file within a specific Folder and execute certain actions (here: copy the file into another folder) if the file is modified and saved (i.e. when the file's timestamp changes):
Option Explicit
Const SourcePath = "C:\YourFolder\"
Const TargetPath = "C:\YourFolder\YourFolder_Changes\"
Const TargetFile = "YourFileName"
Private m_blnLooping As Boolean
Private Sub CommandButton1_Click()
Dim FSO As Scripting.FileSystemObject
Dim n, msg, dt, inttext As String
Dim file, files As Object
Dim d1, d2 As Date
Dim cnt As Integer
Dim wsshell
Application.ScreenUpdating = False
On Error Resume Next
Set FSO = CreateObject("Scripting.FileSystemObject")
Set files = FSO.GetFolder(SourcePath).files
Set wsshell = CreateObject("WScript.Shell")
msg = "FileWatcher started. Monitoring of " & TargetFile & " in progress."
cnt = 0
'Initialize: Loop through Folder content and get file date
For Each file In files
n = file.name
'Get Initial SaveDate of Target File
If n = TargetFile Then
d1 = file.DateLastModified
End If
Next file
m_blnLooping = True
inttext = wsshell.popup(msg, 2, "FileWatcher Ready", vbInformation)
'Message Box should close after 2 seconds automatically
Shell "C:\WINDOWS\explorer.exe """ & TargetPath & "", vbNormalFocus
'Open Windows Explorer and display Target Directory to see changes
Do While m_blnLooping
For Each file In files
n = file.name
If n = TargetFile Then
d2 = file.DateLastModified
If d2 > d1 Then
dt = Format(CStr(Now), "yyyy-mm-dd_hh-mm-ss")
'FSO.CopyFile (SourcePath & TargetFile), (TargetPath & Left(TargetFile, Len(TargetFile) - 4) & "_" & dt & ".txt"), True 'Option with file name extension
FSO.CopyFile (SourcePath & TargetFile), (TargetPath & TargetFile & "_" & dt), True 'Option without file name extension
cnt = cnt + 1
d1 = d2
End If
End If
Next file
'Application.Wait (Now() + CDate("00:00:02")) 'wait 2 seconds, then loop again
DoEvents
Loop
msg = "File " & TargetFile & " has been updated " & cnt & " times."
inttext = wsshell.popup(msg, 2, "FileWatcher Closed", vbInformation)
'Message Box should close after 2 seconds automatically
Application.ScreenUpdating = True
End Sub
Private Sub CommandButton2_Click()
m_blnLooping = False
End Sub
The procedure is activated via a CommandButton ("START") and loops through the speficied Folder (keeps watching the file) until another CommandButton ("STOP") is pressed. You may, however, need to adjust the code to monitor file creation instead of file changes (file.DateCreated instead of file.DateLastModified). The Code is just meant to provide you hint that might solve your Problem.

Excel macro to read input from files created today only

I have an application that exports daily reports in txt format.
I have a macro that extracts certain lines of data from those reports and puts them in an output xls file. my macro's input directory is curently a separate folder that i manually move today's reports into.
I'd like for my macro to be able to just read from the default report folder and only read files created with today's date.
the naming convention of the report files is as follows:
1101_16_16_AppServiceUser_YYYYMMDDhhmmssXXX.txt
not sure what the last 3 digits on the file name represents, but they're always numbers.
Help?
WOW that was fast! thanks... fist time using stackoverflow.
I guess i should include the code that pulls data and dumps it to excel... here it is:
Sub PullLinesFromEPremisReport()
Dim FileName, PathN, InputLn As String
Dim SearchFor1, SearchFor2, OutpFile As String
Dim StringLen1, StringLen2 As Integer
Dim colFiles As New Collection
Dim bridgekey As String
PathO = "C:\Documents and Settings\GROMERO\Desktop\CM reconciliation\output\"
PathN = "C:\Documents and Settings\GROMERO\Desktop\CM reconciliation\input\"
FileName = Dir(PathN)
While FileName <> ""
colFiles.Add (FileName)
FileName = Dir
Wend
SearchFor1 = "BRIDGE KEY"
StringLen1 = Len(SearchFor1)
OutpFile = "RESULTS.xls"
Open PathO & OutpFile For Output As #2
For Each Item In colFiles
Open PathN & Item For Input As #1
Do Until EOF(1) = True
Line Input #1, InputLn
If (Left(LTrim$(InputLn), StringLen1) = SearchFor1) Then
bridgekey = InputLn
End If
Loop
Close #1
Next Item
Close #2
End Sub
Daniel's answer is correct, but using the FileSystemObject requires a couple of steps:
Make sure you have a reference to "Microsoft Scripting Runtime":
Then, to iterate through the files in the directory:
Sub WorkOnTodaysReports()
'the vars you'll need
Dim fso As New FileSystemObject
Dim fldr As Folder
Dim fls As Files
Dim fl As File
Set fldr = fso.GetFolder("C:\Reports")
Set fls = fldr.Files
For Each fl In fls
'InStr returns the position of the substring, or 0 if not found
' EDIT: you can explicitly use the reliable parts of your file name
' to avoid false positives
If InStr(1, fl.Name, "AppServiceUser_" & Format(Now, "YYYYMMDD")) > 0 Then
'Do your processing
End If
Next fl
End Sub
EDIT: So I think, from the code you posted, you could send PathN to the main Reports folder like you desire, then just modify your While statement like so:
While FileName <> ""
If InStr(1, FileName, "AppServiceUser_" & Format(Now, "YYYYMMDD")) > 0 Then
colFiles.Add (FileName)
End If
FileName = Dir
Wend
Two ways you can do this off the top of my head. Assuming you are using a File via the FileSystemObject.
Do an Instr on the file.Name looking for Format(Date, "YYYYMMDD") within the string.
Or use a far simpler approach loop through the files and within your loop do this:
If File.DateCreate >= Date Then
'Do something
end if
Where File is the actual variable used to for looping through the files.
If fileName like "*AppServiceUser_" & Format(Now, "YYYYMMDD") & _
"#########.txt" Then
'good to go
End If