Excel won't let macro save spreadsheet with macros - excel

I've written a spreadsheet for a small company, that has several useful functions including performing the shift rotation for their full- and part-time employees, generates a list of possibly understaffed shifts and then prompts the user to save the updated file with a suggested new name. However I code it, I run into one of 2 problems:
The macro is able to save the spreadsheet without the macros - but then subsequent adjustments to the scheduling won't be reflected in the list of understaffed shifts because the macro isn't saved with the file.
The macro attempts to save the spreadsheet with the macros - but returns an error message, regardless of the parameters I pass the Workbook.SaveAs method. I would have expected that if I saved it with FileFormat=xlOpenXMLWorkbookMacroEnabled and a .xlsm suffix, then there'd be no problem. Instead I get an error message (sorry I don't have it in front of me) to the effect that Excel can't save the spreadsheet in that format. If I manually save the spreadsheet in that format, I have no problem.
I suspect this has to do with safeguards against VBA viruses, but I'm not sure how else to create the functionality I need. The office staff are not computer professionals by any stretch of the imagination, so I need to keep it simple. We also need a record of past rotations, so staff can look back on previous adjustments. At the same time, they want to be able to make adjustments to the current rotation and then re-generate the list of understaffed shifts, or clear it and start again.
I've checked similar forums and posts and the thing that usually does the trick, making sure the filename suffix is in line with the FileType parameter, doesn't seem to have worked here. Any suggestions?
Public Sub SaveSchedule()
Dim SaveName As String
Dim SaveDlg As Office.FileDialog
With Excel.ActiveWorkbook.Worksheets("Workers")
SaveName = "Shift Schedule " & Year(.Range("StartDate"))
SaveName = SaveName & "-" & Right("00" & Month(.Range("StartDate")), 2)
SaveName = SaveName & "-" & Right("00" & Day(.Range("StartDate")), 2)
SaveName = SaveName & " to " & Year(.Range("EndDate"))
SaveName = SaveName & "-" & Right("00" & Month(.Range("EndDate")), 2)
SaveName = SaveName & "-" & Right("00" & Day(.Range("EndDate")), 2)
SaveName = SaveName & ".xlsm" '".xlsx"
End With
Set SaveDlg = Application.FileDialog(msoFileDialogSaveAs)
With SaveDlg
.AllowMultiSelect = False
.ButtonName = "Save"
.InitialFileName = SaveName
.Title = "Save new shift schedule"
If .Show() Then
Excel.ActiveWorkbook.SaveAs .SelectedItems(1), xlOpenXMLWorkbookMacroEnabled ' xlOpenXMLWorkbook
Else
MsgBox SaveName & " should be saved as a new file.", vbCritical + vbApplicationModal + vbOKOnly, "New Schedule not saved."
End If
End With
End Sub

The issue with Application.FileDialog(msoFileDialogSaveAs) is that if you do not specify a correct filter index then it will either pick the first one
OR the one which was used last. This can be resolved by specifying .FilterIndex. For .xlsm. the filter index is 2.
Try this
With SaveDlg
.AllowMultiSelect = False
.ButtonName = "Save"
.InitialFileName = SaveName
.FilterIndex = 2 '<~~ FILTER INDEX
.Title = "Save new shift schedule"
If .Show() Then
Excel.ActiveWorkbook.SaveAs .SelectedItems(1), xlOpenXMLWorkbookMacroEnabled ' xlOpenXMLWorkbook
Else
MsgBox SaveName & " should be saved as a new file.", vbCritical + vbApplicationModal + vbOKOnly, "New Schedule not saved."
End If
End With
OTHER OPTIONS
OPTION 1 : Directly save the file
Dim SaveName As String
With Excel.ActiveWorkbook.Worksheets("Workers")
SaveName = "Shift Schedule " & Year(.Range("StartDate"))
SaveName = SaveName & "-" & Right("00" & Month(.Range("StartDate")), 2)
SaveName = SaveName & "-" & Right("00" & Day(.Range("StartDate")), 2)
SaveName = SaveName & " to " & Year(.Range("EndDate"))
SaveName = SaveName & "-" & Right("00" & Month(.Range("EndDate")), 2)
SaveName = SaveName & "-" & Right("00" & Day(.Range("EndDate")), 2)
SaveName = SaveName & ".xlsm" '".xlsx"
End With
Excel.ActiveWorkbook.SaveAs Filename:=SaveName, FileFormat:=xlOpenXMLWorkbookMacroEnabled
OPTION 2 : Let user only choose a folder
In this option user will not be able to modify the file name and extension. They can only choose the Save As folder.
Option Explicit
Sub Sample()
Dim SaveName As String
Dim Extn As String
Dim FlFormat As Integer
With Excel.ActiveWorkbook.Worksheets("Workers")
SaveName = "Shift Schedule " & Year(.Range("StartDate"))
SaveName = SaveName & "-" & Right("00" & Month(.Range("StartDate")), 2)
SaveName = SaveName & "-" & Right("00" & Day(.Range("StartDate")), 2)
SaveName = SaveName & " to " & Year(.Range("EndDate"))
SaveName = SaveName & "-" & Right("00" & Month(.Range("EndDate")), 2)
SaveName = SaveName & "-" & Right("00" & Day(.Range("EndDate")), 2)
SaveName = SaveName
End With
'~~> File extenstion. I have shown only for 2
'~~> Tweak for rest
Extn = ".xlsm" '".xlsx"
If Extn = ".xlsm" Then
FlFormat = xlOpenXMLWorkbookMacroEnabled
ElseIf Extn = ".xlsx" Then
FlFormat = xlOpenXMLWorkbook
End If
'~~> Folder Browser
Dim Ret As Variant
Ret = BrowseForFolder
If Ret = False Then Exit Sub
Dim Filepath As String
Filepath = Ret
If Right(Filepath, 1) <> "\" Then Filepath = Filepath & "\"
SaveName = Filepath & SaveName & Extn
Excel.ActiveWorkbook.SaveAs Filename:=SaveName, FileFormat:=FlFormat
End Sub
Function BrowseForFolder(Optional OpenAt As Variant) As Variant
Dim ShellApp As Object
Set ShellApp = CreateObject("Shell.Application"). _
BrowseForFolder(0, "Please choose a folder", 0, OpenAt)
On Error Resume Next
BrowseForFolder = ShellApp.self.Path
On Error GoTo 0
Set ShellApp = Nothing
Select Case Mid(BrowseForFolder, 2, 1)
Case Is = ":"
If Left(BrowseForFolder, 1) = ":" Then GoTo CleanExit
Case Is = "\"
If Not Left(BrowseForFolder, 1) = "\" Then GoTo CleanExit
Case Else
GoTo CleanExit
End Select
Exit Function
CleanExit:
BrowseForFolder = False
End Function

SaveAs Dialog
Public Sub SaveSchedule()
Const PROC_TITLE As String = "Save New Shift Schedule"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets("Workers")
Dim SaveName As String
With ws
SaveName = "Shift Schedule " & Format(.Range("StartDate"), "YYYY-MM-DD")
SaveName = SaveName & " to " & Format(.Range("EndDate"), "YYYY-MM-DD")
SaveName = SaveName & ".xlsm"
End With
Dim SaveDlg As Office.FileDialog
Set SaveDlg = Application.FileDialog(msoFileDialogSaveAs)
With SaveDlg
.AllowMultiSelect = False
.ButtonName = "SaveAs"
.FilterIndex = 2 ' .xlsm
.InitialFileName = SaveName
.Title = PROC_TITLE
Dim FilePath As String
If .Show Then
FilePath = .SelectedItems(1)
If StrComp(Right(FilePath, 5), ".xlsm", vbTextCompare) = 0 Then
Application.DisplayAlerts = False ' overwrite, no confirmation
wb.SaveAs FilePath, xlOpenXMLWorkbookMacroEnabled
Application.DisplayAlerts = True
Else ' not '.xlsm'
MsgBox "The file needs to be saved with an '.xlsm' extension." _
& vbLf & "File not saved.", _
vbCritical + vbApplicationModal, PROC_TITLE
End If
Else ' canceled
MsgBox SaveName & " not saved.", _
vbCritical + vbApplicationModal, PROC_TITLE
End If
End With
End Sub

Related

How to save invoice created in excel using VBA

Save invoice that automate into folder according to month. Means that if the invoice date on 15 January 2023 so when it save will go to January folder not the other month such as May June etc.
Sub SaveInvoice()
Dim path As String
Dim MyFile As String path = "\\Japan\admin\Planning & Costing\Finance\Billing\DATA BILLING\IMPORT\2023\"
MyFile = Range("C13") & "_" & Range("H11") & "_" & Range("J13").Text 
'create invoice in XLSX format
ActiveWorkbook.SaveAs Filename:=path & MyFile & ".xls", FileFormat:=xlOpenXMLWorkbookMacroEnabled 
'ActiveWorkbook.Close
Application.DisplayAlerts = True 
MsgBox "Saving Complete! Thank you~" 
End Sub
Save File in Subfolders By Year and By Month
Sub SaveInvoice()
Const DST_INITIAL_PATH As String = "\\Japan\admin\" _
& "Planning & Costing\Finance\Billing\DATA BILLING\IMPORT\"
If Len(Dir(DST_INITIAL_PATH, vbDirectory)) = 0 Then
MsgBox "The initial path """ & DST_INITIAL_PATH & """doesn't exist.", _
vbCritical
Exit Sub
End If
Dim iDate As Date: iDate = Date ' today
Dim dPath As String: dPath = DST_INITIAL_PATH & Format(iDate, "yyyy") & "\"
If Len(Dir(dPath, vbDirectory)) = 0 Then MkDir dPath
dPath = dPath & Format(iDate, "mmmm") & "\"
If Len(Dir(dPath, vbDirectory)) = 0 Then MkDir dPath
Dim dws As Worksheet: Set dws = ActiveSheet ' improve!
Dim dFileName As String: dFileName = dws.Range("C13").Text _
& dws.Range("H11").Text & dws.Range("J13").Text & ".xlsx"
With dws.Parent
Application.DisplayAlerts = False ' to overwrite without confirmation
.SaveAs Filename:=dPath & dFileName, FileFormat:=xlOpenXMLWorkbook
Application.DisplayAlerts = True
.Close SaveChanges:=False
End With
MsgBox "Saving Complete! Thank you.", vbInformation
End Sub

Loop to save worksheet in new workbook

I want to run through a specific sheet (from & to) save those ws as a new file in a folder, if the folder doesn't exist then create.
I'm able to do it to one sheet.
ActiveSheet.Next.Select
If Range("F3").Value = "" Then
Windows("Import OT.xlsm").Activate
Sheets("Cash").Select
Dim filename101 As String
Dim path101 As String
Application.DisplayAlerts = False
path101 = Environ("UserProfile") & "\Dropbox\A271\5 Oppgjor\" & 2020 & "\"
filename101 = Range("B1").Value & ".xlsx"
ActiveWorkbook.SaveAs path101 & Range("A2") & "\" & Range("A1") & " " & filename101,xlOpenXMLWorkbook
Application.DisplayAlerts = True
Else
Cells.Select
Range("F3").Activate
Selection.Copy
Workbooks.Add
ActiveSheet.Paste
Dim Path1 As String
Dim fpathname1 As String
Path1 = Environ("UserProfile") & "\Dropbox\A271\4 Lonnslipper\"
fpathname1 = Path1 & Range("F3") & "\" & Range("F2") & " " & Range("B3") & ".xlsx"
path01 = Environ("UserProfile") & "\Dropbox\A271\4 Lonnslipper\" & Range("F3")
Dim path001 As String
Dim Folder As String
Folder = Dir(path01, vbDirectory)
If Folder = vbNullString Then
VBA.FileSystem.MkDir (path01)
ActiveWorkbook.SaveAs filename:=fpathname1, FileFormat:=51
ActiveWorkbook.Close
Sheets("Cash").Select
Else
ActiveWorkbook.SaveAs filename:=fpathname1, FileFormat:=51
ActiveWorkbook.Close
Sheets("Cash").Select
End If
End If
End Sub
I want this as a loop is because I have a few tens of sheets. For it to work I think I need to write it specific time, but with loop I learned I don't need to do that.
Excel file sheet
https://onedrive.live.com/view.aspx?resid=AF6FF2618C09AC74!29027&ithint=file%2cxlsx&authkey=!AHcJjYCu8D0NTNY
According to your comment where you wrote the steps:
Read the comments
Try to run the code using F8 key and see where you need to change it.
As you're learning, please note to first write the steps in plain English Norsk and then develop your code.
See how I just followed your steps with readable code.
Code:
Public Sub GenerateCustomersFiles()
' 1) Active sheet (oppgjør 1-20)
Dim targetSheet As Worksheet
For Each targetSheet In ThisWorkbook.Sheets
' Check only sheets with string in name
If InStr(targetSheet.Name, "Oppgjør") > 0 Then
' 2) look if value in F3 is empty
If targetSheet.Range("F3").Value = vbNullString Then
' 3) if it is, do select "cash" sheet and save this file (its name and path are given above what it should be named)
Dim fileName As String
Dim filePath As String
Dim folderPath As String
folderPath = Environ("UserProfile") & "\Dropbox\A271\5 Oppgjor\" & 2020 & "\"
fileName = targetSheet.Range("B1").Value & ".xlsx"
filePath = folderPath & targetSheet.Range("A2") & "\" & targetSheet.Range("A1") & " " & fileName
ThisWorkbook.Worksheets("Cash").Select
ThisWorkbook.SaveAs filePath, xlOpenXMLWorkbook
Else
' 4) if it doesn't, do open selected sheet to a new workbook and save that in clients name folder (folder and path given above in code section)
folderPath = Environ("UserProfile") & "\Dropbox\A271\4 Lonnslipper\" & targetSheet.Range("F3")
fileName = targetSheet.Range("F2") & " " & targetSheet.Range("B3") & ".xlsx"
filePath = folderPath & "\" & fileName
' 5) check if clients folder exist or not for the file to be saved in.
' if folder doesnt exist,
' create new and save file there.
CreateFoldersInPath folderPath
' if folder exist just save the file there
Dim targetWorkbook As Workbook
Set targetWorkbook = Workbooks.Add
targetSheet.Copy before:=targetWorkbook.Sheets(1)
targetWorkbook.SaveAs filePath, 51
targetWorkbook.Close
End If
End If
Next targetSheet
End Sub
' Credits: https://stackoverflow.com/a/31034201/1521579
Private Sub CreateFoldersInPath(ByVal targetFolderPath As String)
Dim strBuildPath As String
Dim varFolder As Variant
If Right(targetFolderPath, 1) = "\" Then targetFolderPath = Left(targetFolderPath, Len(targetFolderPath) - 1)
For Each varFolder In Split(targetFolderPath, "\")
If Len(strBuildPath) = 0 Then
strBuildPath = varFolder & "\"
Else
strBuildPath = strBuildPath & varFolder & "\"
End If
If Len(Dir(strBuildPath, vbDirectory)) = 0 Then MkDir strBuildPath
Next varFolder
'The full folder path has been created regardless of nested subdirectories
'Continue with your code here
End Sub
Let me know how it goes

Suppress Save as pdf dialog box

i need a modification in this code to suppress save as dialogbox(save file as pdf in mentioned location (C:\Users\hazem\Desktop\New folder (4)\HM\PDF) without any save as screen appears and without excel workbook name changed)_
note :_
i work on windows 10 ,excel ver. 2019
this code is part of macro
(Application.DisplayAlerts = False _
""code between""_
Application.DisplayAlerts = true)
doesn't work with me
This is the code:
Sub PDFActiveSheet()
Dim wsA As Worksheet
Dim wbA As Workbook
Dim strTime As String
Dim strName As String
Dim strPath As String
Dim strFile As String
Dim strPathFile As String
Dim MyFile As Variant
Dim answer As Integer
Dim fnd As Variant
Dim rplc As Variant
Filename1 = Range("B4")
filename2 = Range("G11")
filename3 = Range("M4")
filename4 = Range("B4")
filename5 = Range("B5")
filename6 = Range("C5")
Set wbA = ActiveWorkbook
Set wsA = ActiveSheet
strTime = Format(Now(), "yyyy-mm-dd_hhmm")
strPath = "C:\Users\hazem\Desktop\New folder (4)\HM\PDF"
If strPath <> "C:\Users\hazem\Desktop\New folder (4)\HM\PDF" Then
Exit Sub
End If
strPath = strPath & "\"
'replace spaces and periods in sheet name
strName = Replace(wsA.Name, " ", "")
strName = Replace(strName, ".", "_")
'create default name for savng file
strFile = Filename1 & "_" & filename3 & " " & "of" & " " & filename2 & " " & "at" & " " & strTime & ".pdf"
strPathFile = strFile
'use can enter name and
' select folder for file
answer = MsgBox("Please!! Save the PDF to path (FINISHED CRS PDF OF SELECTED AUTHORITY) ", vbQuestion + vbYesNo + vbDefaultButton2, "CRS PDF CREATOR")
If answer = vbNo Then MsgBox "Please! Try again Later"
If answer = vbNo Then Exit Sub
Application.DisplayAlerts = False
ActiveWorkbook.Close savechanges:=True
MyFile = Application.GetSaveAsFilename _
(InitialFileName:=strPathFile, _
FileFilter:="PDF Files (*.pdf), *.pdf", _
Title:="Select Folder and FileName to save")
Application.DisplayAlerts = False
If MyFile = Cancel Then Exit Sub
'export to PDF if a folder was selected
MsgBox "PDF file wil be opened in seconds "
MsgBox "please click CTRL+P to print PDF and change copies to the no. you need"
If MyFile <> "False" Then
Application.EnableEvents = False
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=MyFile, _
Quality:=xlQualityStandard, IncludeDocProperties:=True, _
IgnorePrintAreas:=False, OpenAfterPublish:=True
Application.EnableEvents = True
'confirmation message with file info
MsgBox "PDF file has been created: " _
& vbCrLf _
& MyFile
MsgBox "Your Work is done here!"
MsgBox "Thank you"
End If
End sub

I want to save new file and create file in new folder in 'Documents'

I have a macro to save file to 'MyDocuments', but I don't want user to have it cluttered with a bunch of other files that may already be in there, so I want it to save to a new folder called "DriverLog". I have tried putting SpecialFolders("MyDocuments\DriverLog\") but says it does not exist.
Here is my code:
Sub SaveBook()
'----------------------------------------------------
'Save File to Hard Drive
'----------------------------------------------------
Dim sFile As String
sFile = Range("G2").Value & "_DriverLog" & ".xlsm"
ActiveWorkbook.SaveAs Filename:=CreateObject("WScript.Shell").SpecialFolders("MyDocuments\") & sFile, FileFormat:=52
MsgBox ("This has been saved as '") & CreateObject("WScript.Shell").SpecialFolders("MyDocuments\") & sFile & ("' in your documents folder.")
End Sub
Code works to save file by itself no problem... I just can't make the new folder.
Mine is a simplified version of the code.
'----------------------------------------------------
'Save File to Hard Drive
'----------------------------------------------------
Dim sFile As String
Dim sPath As String
sPath = "C:\Users\User\MyDocuments\DriverLog"
sFile = Range("G2").Value & "_DriverLog" & ".xlsm"
If Len(Dir(sPath, vbDirectory)) = 0 Then 'Added This line to create new folder
MkDir (sPath)
End If
ActiveWorkbook.SaveAs Filename:=sPath & "\" & sFile
MsgBox ("This has been saved as ") & sPath & "\" & sFile
This should work for you. The CreateDirectory Sub is a common routine I use for this task.
Sub SaveBook()
'----------------------------------------------------
'Save File to Hard Drive
'----------------------------------------------------
Dim sFile As String
Dim sPath As String
Dim sPS As String
sPS = Application.PathSeparator
sPath = Environ("UserProfile") & sPS & "Documents" & sPS & "DriverLog" & sPS
CreateDirectory sPath
If Len(Dir(sPath, vbDirectory)) = 0 Then Exit Sub 'Couldn't create the path due to invalid or inaccessible location
sFile = Range("G2").Value & "_DriverLog" & ".xlsm"
ActiveWorkbook.SaveAs Filename:=sPath & sFile, FileFormat:=52
MsgBox ("This has been saved as '") & sPath & sFile & ("' in your documents folder.")
End Sub
Sub CreateDirectory(ByVal arg_sFolderpath As String)
If Len(Dir(arg_sFolderpath, vbDirectory)) = 0 Then
Dim sPS As String
sPS = Application.PathSeparator
Dim sBuildPath As String
Dim vFolder As Variant
For Each vFolder In Split(arg_sFolderpath, sPS)
If Len(vFolder) > 0 Then
If Len(sBuildPath) = 0 Then sBuildPath = vFolder Else sBuildPath = sBuildPath & sPS & vFolder
If Len(Dir(sBuildPath, vbDirectory)) = 0 Then
On Error Resume Next
MkDir sBuildPath
On Error GoTo 0
If Len(Dir(sBuildPath, vbDirectory)) = 0 Then
MsgBox "[" & sBuildPath & "] is either invalid or unreachable.", , "Create Directory Error"
Exit Sub
End If
End If
End If
Next vFolder
End If
End Sub

Saving an excel file based on prepopulated cells

I made a Commandbutton that will allow the user to save the file based on the values within the excel cells in which the cells are pre-populated to begin with. Also how do you implement this fuction GetSaveAsFilename so the user can choose a save destination but not change the title. But I am getting an error executing this code.
Private Sub CommandButton2_Click()
Sub SaveMyWorkbook()
Dim strPath As String
Dim strFolderPath As String
strFolderPath = "C:\Users\"
strPath = strFolderPath & _
DoNotPrint - Setup.Range("C7").Value & " " & _
DoNotPrint - Setup.Range("C8").Value & " " & _
DoNotPrint - Setup.Range("C45").Value & " " & _
DoNotPrint - Setup.Range("C9").Value & ".xlsm"
End Sub
Best guess:
With Thisworkbook.sheets("DoNotPrint - Setup")
strPath = strFolderPath & .Range("C7").Value & " " & _
.Range("C8").Value & " " & _
.Range("C45").Value & " " & _
.Range("C9").Value & ".xlsm"
End with
Selecting a folder to save to:
VBA EXCEL To Prompt User Response to Select Folder and Return the Path as String Variable
To allow the user to choose the folder I use this:
Private Sub CommandButton2_Click()
Dim strPath As String
Dim strFolderPath As String
strFolderPath = "C:\Users\"
strPath = strFolderPath & _
DoNotPrint - Setup.Range("C7").Value & " " & _
DoNotPrint - Setup.Range("C8").Value & " " & _
DoNotPrint - Setup.Range("C45").Value & " " & _
DoNotPrint - Setup.Range("C9").Value & ".xlsm"
With Application.FileDialog(msoFileDialogSaveAs)
.AllowMultiSelect = False
.InitialFileName = strPath
.FilterIndex = 2
.Title = Place Title Here if you want
If .Show = -1 Then .Execute
End With
End Sub
Based on Tim's and Zack's Answer, this worked
Private Sub CommandButton2_Click()
Dim strPath As String
Dim strFolderPath As String
strFolderPath = "C:\Users\"
With ThisWorkbook.Sheets("DoNotPrint - Setup")
strPath = strFolderPath & .Range("C7").Value & " " & _
.Range("C8").Value & " " & _
.Range("C45").Value & " " & _
.Range("C9").Value & ".xlsm"
End With
With Application.FileDialog(msoFileDialogSaveAs)
.AllowMultiSelect = False
.InitialFileName = strPath
.FilterIndex = 2
If .Show = -1 Then .Execute
End With
End Sub

Resources