Export Excel sheet to PDF using Macros and values of another table - vba

I'm new in Excel Macros and have no experience with VB or any language.
I have a sheet with a Price List, in this we have a field with a dropdown list with Contact Info (mail and cellphone) of our Salesman.
A second sheet contain a table with Name and ContactInfo.
Today, i use the dropdown to choose the salesman and export to pdf to specific directory.
I'm looking to export to PDF using a Macro doing these things. I've tried some macros without success. I want to use the name #Name to save in directory and #ContactInfo to replace in a specific field of pricelist.
What i have:
Sub MAKEPDF()
Dim dvCell As Range
Dim inputRange As Range
Dim c As Range
Dim i As Long
'Which cell has data validation
Set dvCell = Sheets("NUEVA LISTA").Range("A3")
'Determine where validation comes from
Set inputRange = Evaluate(dvCell.Validation.Formula1)
arrVendedores = Array("Name1", "Name2", "Name3", "Name4", "Name5", "Name6", "Name7")
i = 1
'Begin our loop
Application.ScreenUpdating = False
For Each c In inputRange
dvCell = c.Value
ChDir "D:\Google Drive\Lista de Precios\temp\" & arrVendedores(i)
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:="(" & Format(Range("A4"), "yyyy-mm-dd") & ") Lista de precios.pdf"
'Quality:=xlQualityStandard, _
IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:=True
i = i + 1
Next c
Application.ScreenUpdating = True
End Sub
This save in PDF perfectly but that array don't work as expected causing error 9 (index) and is better use current data from Table1#Name.
Can anyone help me to goal this?
Thanks and sorry for my bad english.

I found it hard to edit your code without seeing some of the inputs, but I got this to flow though with some dummy data.
Sub MAKEPDF()
Dim dvCell As Range
Dim inputRange As Range
Dim c As Range
Dim i As Long
Application.ScreenUpdating = False
'Which cell has data validation
Set dvCell = Sheets("NUEVA LISTA").Range("A3")
'You assigned the value of this cell later on but didn't use it so I removed the value assignment below.
'Determine where validation comes from
Set inputRange = Evaluate(dvCell.Validation.Formula1)
arrVendedores = Array("Name1", "Name2", "Name3", "Name4", "Name5", "Name6", "Name7")
'you might want to assign this in code, not sure if it is the sheet names but I assumed it is if not and just filenames to use.
For i = LBound(arrVendedores) To UBound(arrVendedores)
'this allows an array of any size to be iterated over with having to change the code.
ChDir "D:\Google Drive\Lista de Precios\temp\" & arrVendedores(i)
Worksheets(arrVendedores(i)).ExportAsFixedFormat Type:=xlTypePDF, Filename:="(" & Format(Range("A4"), "yyyy-mm-dd") & ") Lista de precios.pdf"
'you had activeworksheet here but it didn't seem to be changing, so if I assume the array is sheet names this will export those sheet else you will need to change to suit.
'Quality:=xlQualityStandard, _
IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:=True
Next
Application.ScreenUpdating = True
End Sub

Thank you Captain, based on your answer i made a new macro as following
Sub MakePDF4()
Dim myTable As ListObject
Dim myArray As Variant
Dim x As Long
Dim vendedorDatos As Range
Dim vendedorCampoDatos As Range
Set myTable = Sheets("VENDEDORES").ListObjects("Table1")
myArray = myTable.DataBodyRange
For x = LBound(myArray) To UBound(myArray)
Application.ScreenUpdating = False
Set vendedorCampoDatos = (Sheets("NUEVA LISTA").Range("A3"))
vendedorCampoDatos = myArray(x, 2)
'ChDir "D:\Google Drive\Lista de Precios\temp\" & myArray(x, 1)
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:="D:\Google Drive\Lista de Precios\temp\" & myArray(x, 1) & "\(" & Format(Range("A4"), "yyyy-mm-dd") & ") Lista de precios.pdf"
'Quality:=xlQualityStandard, _
IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:=True
Next x
Application.ScreenUpdating = True
End Sub
It work as expected. I have some issue with setting ChDir with the array at the end but works when is setting in filename.
All data is in a unique file (may be i mispelled or confuse some words at explaining). One worksheet is the price list and a second worksheet contains the table with [#Name] and [#ContactInfo] of salesmen.
I use [#Name] to determinate in which directory i will save the PDF file and [#ContactInfo] to change in the worksheet of price list a unique field between salesmen

Related

Check if there's been data copied/pasted from a excel file (VBA)

Im going to start by telling what my intention was with this code
In my job we have to open every sales order that will be sent in that day and check for the itens to be shipped manually.
Since its very time consuming i tought in creating a worksheet that it will look for the itens in every sales order and copy/paste in my master so i can know what i need to get.
However to my sheet works I had to make a few changes in the Sales order, but now I want to create a error check, that if the file that it was open was an older SO it will tell me its order number so later i can check it.
Also i want to check if by some reason nothing was found in that SO.
Now ill explain what my code does (I have a little knowledge in coding and in excel vba, so please dont judge my ugly script)
Using the value of a cell in a range, it will open the folder and file that matches it's value, then will look for a specific range and for a specific cell value, in this case "Perfil", if this value is found it will copy some cells.
After looking for that file it will open another one and do the same.
However if "Perfil" is not found it wont copy and paste anything and it will just go to the next file.
Public Sub test()
On Error GoTo Errormsg
Dim wbk As Workbook
Dim Fonte As Workbook
Dim Dest As Workbook
Dim Filename As String
Dim FolderName As String
Dim Arquivo As String
Dim Path As String
Dim celula As Range
Dim cll As Range
Dim Inicio As Range
Dim Fim As Range
Dim OffInicio As Range
Dim OffFim As Range
Dim busca As Range
Application.ScreenUpdating = False
Set Dest = Workbooks("testee.xlsm")
Path = 'My file path
lrow = Sheets(1).Range("A" & Sheets(1).Rows.Count).End(xlUp).Row
For Each celula In Dest.Worksheets(1).Range("A3:A" & lrow)
Dest.Sheets(1).Activate
Pedido = Cells(celula.Row, 1)
FolderName = Pedido & "*"
Arquivo = "\" & Pedido
Folder = Dir(Path & FolderName, vbDirectory)
Filename = Dir(Path & Folder & Arquivo & "*.xlsx")
Set wbk = Workbooks.Open(Path & Folder & "\" & Filename, 0)
Set Fonte = Workbooks(Filename)
Fonte.Activate
Set Inicio = Fonte.Worksheets(1).Cells.Find(what:="MODO DE FIXAÇÃO DO PRODUTO")
Set Fim = Fonte.Worksheets(1).Cells.Find(what:="OBSERVAÇÕES")
Set OffInicio = Inicio.Offset(1, 0)
Set OffFim = Fim.Offset(-1, 1)
Set busca = Range(OffInicio, OffFim).Columns(5)
Set check = Range(OffInicio, OffFim).Columns(9)
Range(OffInicio, OffFim).Columns(5).Select
Set busca = Selection
For Each cl In busca
tipo = Cells(cl.Row, 5).Value
If tipo = "Perfil" Then
tamanho = Cells(cl.Row, 6).Value
expessura = Cells(cl.Row, 11).Value
cor = Cells(cl.Row, 12).Value
lrow2 = Dest.Sheets(2).Range("D" & Dest.Sheets(2).Rows.Count).End(xlUp).Row
linha = lrow2 + 1
Dest.Sheets(2).Range("D" & linha).Value = Pedido
Dest.Sheets(2).Range("E" & linha).Value = tamanho
Dest.Sheets(2).Range("H" & linha).Value = cor
End If
Next cl
End If
Next celula
Errormsg:
lrow2 = Dest.Sheets(2).Range("D" & Dest.Sheets(2).Rows.Count).End(xlUp).Row
linha = lrow2 + 1
Dest.Sheets(2).Range("D" & linha).Value = Pedido
Dest.Sheets(2).Range("E" & linha).Value = "Pedido com modelo Antigo"
End Sub
I want to know the files that no data has been copied, so I can check manually and see why it wasnt.
To do that i tought in checking if in that file any data has been copied and pasted in my master sheet, if nothing was done it will send a message in a cell telling its number so i can check it later.
Now is my question:
I dont know if is possible to check if anything was pasted from that file, in case is possible, how i do that?
I cant just check if "Perfil" exists because for my sheet works I had to change a few things in the sheets that had the data I needed, and "perfil"is not something that the older version of it had.
Also in my new version "Perfil"is not the only value that the column can have so i cant just check if perfil is not found there.
There are a few ways you can check if anything has changed in the workbook. I'd suggest this method:
In any (new or existing) standard module, add a public variable declaration at or near the top of the module:
Public wksChanged As Boolean
For each worksheet that you want to monitor for changes, open the Worksheet's module by right-clicking the worksheet's tab and clicking View Code:
...and then add this procedure (to each applicable worksheet module):
Private Sub Worksheet_Change(ByVal Target As Range)
wksChanged = True
End Sub
wksChanged will default to False when the workbook is first opened, and will change to True when any cell is changed. You can "reset" it at any time with:
wksChanged = False

Shorter way to test range for a certain string

Trying to create code that will export my Excel invoice sheet to PDF, to a specified file path. The path is based on the whether the invoice lists a certain product, ProductX.
This is what I came up with, but seems cumbersome to loop through every single cell in a range to see if ProductX is there.
Is there an easier way to do this? Appreciate any help!
Sub ExportToPDF()
'
Dim file_path As String
Dim search_range As Range
Dim each_cell As Range
' Set search_range as desired search range
Set search_range = ActiveSheet.Range("A53:R56")
For Each each_cell In search_range.Cells
If InStr(1, each_cell.Value, "ProductX", vbTextCompare) Then
file_path = Some_path_A
Else: file_path = Some_path_B
End If
Next each_cell
'Export the sheet as PDF
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, FileName:=file_path, Quality:=xlQualityStandard _
, IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:= _
True
End Sub
You can use Find for a partial match.
This code assumes that the returned path contains the filepath variable you need - you may need to tweak this.
Dim rng1 As Range
Set rng1 = ActiveSheet.Range("A53:R56").Find("ProductX", , xlFormulas, xlPart)
If rng1 Is Nothing Then Exit Sub
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:=rng1.Value, Quality:=xlQualityStandard _
, IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:= _
True
Based on what brettdj has suggested, you can use the proposed code like below...
Sub ExportToPDF()
Dim file_path As String
Dim search_range As String
Dim each_cell As Range
Dim rng1 As Range
' Set search_range as desired search range
search_range = ActiveSheet.Range("A53:R56")
Set rng1 = ActiveSheet.Range("A53:R56").Find("ProductX", , xlFormulas, xlPart)
If Not rng1 Is Nothing Then
file_path = Some_path_A
Else
file_path = Some_path_B
End If
'Export the sheet as PDF
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:=file_path, Quality:=xlQualityStandard _
, IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:= _
True
End Sub
I think the shortest way is the following:
If WorksheetFunction.CountIf(ActiveSheet.Range("A53:R56"), "*ProductX*") = 0 Then Exit Sub
which can be further reduced to:
If WorksheetFunction.CountIf(Range("A53:R56"), "*ProductX*") = 0 Then Exit Sub
since ActiveSheet is the default ragnge worksheet qualification
There is a way to find exactly that with just a line of code however it will work only the if you search on 1 column. For your case I think it will work because usually the product name will be in a column. The code is as follows:
Dim test As Variant
Product = "ProductX"
' Set search_range as desired search range
search_range = Application.WorksheetFunction.Transpose(Sheets(1).Range("A53:A56"))
If UBound(Filter(search_range, Product)) > -1 Then
file_path = Some_path_A
Else
file_path = Some_path_B
End If
You can give it a try and let me know if this works for you. If not I will try to find a way to do it with multiple columns and improve the answer

AutoFilter method of Range class failed in VB.NET

I am trying to use some Parsing i was able to tweak a little. If I use it in straight VBA in excel, it works fine. However, when I use the same code as a module in VB.NET I get the error in the title on the line of code
ws.Range(vTitles).AutoFilter()
(duh!) I am not sure what is going wrong in the conversion, since I am not a hardcore VB.Net programmer, so I am doing a lot of googling, but not finding much that works. Any ideas on how this could be fixed or do I have to abandon the idea of using this snippet in VB.Net?
Here is the code I am using:
'turned strict off or autofilter per http://www.pcreview.co.uk/threads/autofilter-method-of-range-class-failed.3994483/
Option Strict Off
Imports xl = Microsoft.Office.Interop.Excel
Module ParseItems
Public Sub ParseItems(ByRef fileName As String)
'Jerry Beaucaire (4/22/2010)
'Based on selected column, data is filtered to individual workbooks are named for the value plus today's date
Dim wb As xl.Workbook
Dim xlApp As xl.Application
Dim LR As Long, Itm As Long, MyCount As Long, vCol As Long
Dim ws As xl.Worksheet, MyArr As Object, vTitles As String, SvPath As String
'Set new application and make wb visible
xlApp = New xl.Application
xlApp.Visible = True
'open workbook
wb = xlApp.Workbooks.Open(fileName)
'Sheet with data in it
ws = wb.Sheets("Original Data")
'Path to save files into, remember the final "\"
SvPath = "G:\MC VBA test\"
'Range where titles are across top of data, as string, data MUST have titles in this row, edit to suit your titles locale
vTitles = "A1:L1"
'Choose column to evaluate from, column A = 1, B = 2, etc.
vCol = xlApp.InputBox("What column to split data by? " & vbLf & vbLf & "(A=1, B=2, C=3, etc)", "Which column?", 1, Type:=1)
If vCol = 0 Then Exit Sub
'Spot bottom row of data
LR = ws.Cells(ws.Rows.Count, vCol).End(xl.XlDirection.xlUp).Row
'Speed up macro execution
'Application.ScreenUpdating = False
'Get a temporary list of unique values from key column
ws.Columns(vCol).AdvancedFilter(Action:=xl.XlFilterAction.xlFilterCopy, CopyToRange:=ws.Range("EE1"), Unique:=True)
'Sort the temporary list
ws.Columns("EE:EE").Sort(Key1:=ws.Range("EE2"), Order1:=xl.XlSortOrder.xlAscending, Header:=xl.XlYesNoGuess.xlYes, _
OrderCustom:=1, MatchCase:=False, Orientation:=xl.Constants.xlTopToBottom, DataOption1:=xl.XlSortDataOption.xlSortNormal)
'Put list into an array for looping (values cannot be the result of formulas, must be constants)
MyArr = xlApp.WorksheetFunction.Transpose(ws.Range("EE2:EE" & ws.Rows.Count).SpecialCells(xl.XlCellType.xlCellTypeConstants))
'clear temporary worksheet list
ws.Range("EE:EE").Clear()
'Turn on the autofilter, one column only is all that is needed
ws.Range(vTitles).AutoFilter()
'Loop through list one value at a time
For Itm = 1 To UBound(MyArr)
ws.Range(vTitles).AutoFilter(Field:=vCol, Criteria1:=MyArr(Itm))
ws.Range("A1:A" & LR).EntireRow.Copy()
xlApp.Workbooks.Add()
ws.Range("A1").PasteSpecial(xl.XlPasteType.xlPasteAll)
ws.Cells.Columns.AutoFit()
MyCount = MyCount + ws.Range("A" & ws.Rows.Count).End(xl.XlDirection.xlUp).Row - 1
xlApp.ActiveWorkbook.SaveAs(SvPath & MyArr(Itm), xl.XlFileFormat.xlWorkbookNormal)
'ActiveWorkbook.SaveAs SvPath & MyArr(Itm) & Format(Date, " MM-DD-YY") & ".xlsx", 51 'use for Excel 2007+
xlApp.ActiveWorkbook.Close(False)
ws.Range(vTitles).AutoFilter(Field:=vCol)
Next Itm
'Cleanup
ws.AutoFilterMode = False
MsgBox("Rows with data: " & (LR - 1) & vbLf & "Rows copied to other sheets: " & MyCount & vbLf & "Hope they match!!")
xlApp.Application.ScreenUpdating = True
End Sub
End Module
Looks like you need to specify at least one optional parameter. Try this:
ws.Range(vTitles).AutoFilter(Field:=1)
I realize this was closed years ago, but I recently ran into this problem and wanted to add to the solution.
This seems to only work when specifically using the first optional Field parameter. I attempted this fix using the optional VisibleDropDown parameter and still got this error.
ws.Range["A1"].AutoFilter(VisibleDropDown: true); Gives error
ws.Range["A1"].AutoFilter(Field: 1); No error

Add VBA Conditional Statement to Loop

So I have this code below that currently works. All of the data is on a tab called "Table" and feed into a tab called "Att A" that gets produced into 100+ pdf files and named based on the value that is in column A in the "Table" tab.
I would like to add a conditional statement to the following code that checks the value in column CH in the "Table" tab and if it is greater than 0 save in one location, if it equals 0 then save in another location. Since there are 100+ lines of data, the value in column A needs to check the value in the same row for column CH.
So the logic goes to column A (Uses this value as the file name), creates a file, and checks column CH to determine which folder to save the file in. How do I add this condition to the following code?
Sub Generate_PDF_Files()
Application.ScreenUpdating = False
Sheets("Table").Activate
Range("A7").Activate
Do Until ActiveCell.Value = "STOP"
X = ActiveCell.Value
Range("DLR_NUM") = "'" & X
Sheets("Att A").Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
"L:\Mike89\Sales" & X & ".pdf", Quality:=xlQualityStandard, _IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:=False
Sheets("Table").Activate
ActiveCell.Offset(1, 0).Activate
Loop
End Sub
Since your code works, we would typically suggest you post it on Code Review, however you're also looking for some help on a conditional statement.
So a few quick things...
Avoid Select and Activate
Use Descriptive Variable Naming
Always Define and Set References to Worksheets and Workbooks
Never Assume the Worksheet
The conditional itself is very straightforward as shown in the example below, which also incorporates the ideas shared in the links above:
Option Explicit
Sub Generate_PDF_Files()
Dim tableWS As Worksheet
Dim attaWS As Worksheet
Dim filename As Range
Dim checkValue As Range
Dim filepath As String
Const ROOT_FOLDER1 = "L:\Mike89\Sales"
Const ROOT_FOLDER2 = "L:\Mike99\Sales"
Set tableWS = ThisWorkbook.Sheets("Table")
Set attaWS = ThisWorkbook.Sheets("Att A")
Set filename = tableWS.Range("A7")
Set checkValue = tableWS.Range("CH7")
Application.ScreenUpdating = False
Dim dlrNum as Range
set dlrNum = tableWS.Range("DLR_NUM")
Do Until filename = "STOP"
dlrNum = "'" & filename
If checkValue > 0 Then
filepath = ROOT_FOLDER1 & filename
Else
filepath = ROOT_FOLDER2 & filename
End If
attaWS.ExportAsFixedFormat Type:=xlTypePDF, _
filename:=filepath, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
Set filename = filename.Offset(1, 0)
Set checkValue = checkValue.Offset(1, 0)
Loop
Application.ScreenUpdating = True
End Sub

How to loop through worksheets in a defined order using VBA

I have the below working code which loops through each worksheet and if the value defined in the range (myrange) is 'Y', it outputs those sheets into a single PDF document. My challange is that i want to define the order that they are output in the PDF based on the number value in the range (for example 1,2,3,4,5,6,7 etc) instead of 'Y'. I plan on using the same column in the myrange to check whether it needs to be output to PDF, by simply swapping the 'Y' for a number, such as '1' and '2'.
Currently the order is defined based on the location of the worksheet tabs. from left to right.
Any help will be much appreciated.
Sub Run_Me_To_Create_Save_PDF()
Dim saveAsName As String
Dim WhereTo As String
Dim sFileName As String
Dim ws As Worksheet
Dim printOrder As Variant '**added**
Dim myrange
On Error GoTo Errhandler
Sheets("Settings").Activate
' Retrieve value of 'Period Header' from Settings sheet
Range("C4").Activate
periodName = ActiveCell.Value
' Retrieve value of 'File Name' from Settings sheet
Range("C5").Activate
saveAsName = ActiveCell.Value
' Retrieve value of 'Publish PDF to Folder' from Settings sheet
Range("C6").Activate
WhereTo = ActiveCell.Value
Set myrange = Worksheets("Settings").Range("range_sheetProperties")
' Check if Stamp-field has any value at all and if not, add the current date.
If Stamp = "" Then Stamp = Date
' Assemble the filename
sFileName = WhereTo & saveAsName & " (" & Format(CDate(Date), "DD-MMM-YYYY") & ").pdf"
' Check whether worksheet should be output in PDF, if not hide the sheet
For Each ws In ActiveWorkbook.Worksheets
Sheets(ws.Name).Visible = True
printOrder = Application.VLookup(ws.Name, myrange, 4, False)
If Not IsError(printOrder) Then
If printOrder = "Y" Then
Sheets(ws.Name).Visible = True
End If
Else: Sheets(ws.Name).Visible = False
End If
Next
'Save the File as PDF
ActiveWorkbook.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
sFileName, Quality _
:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas:=False, _
OpenAfterPublish:=True
' Unhide and open the Settings sheet before exiting
Sheets("Settings").Visible = True
Sheets("Settings").Activate
MsgBox "PDF document has been created and saved to : " & sFileName
Exit Sub
Errhandler:
' If an error occurs, unhide and open the Settings sheet then display an error message
Sheets("Settings").Visible = True
Sheets("Settings").Activate
MsgBox "An error has occurred. Please check that the PDF is not already open."
End Sub
---------------------- UPDATE: -------------------------------------
Thank you for all your input so far. I did get it to work briefly, but with more playing i've become stuck. I am now receiving a 'Subscript our of range' error with the below code at :
If sheetNameArray(x) <> Empty Then
Any ideas?
Sub Run_Me_To_Create_Save_PDF()
Dim saveAsName As String
Dim WhereTo As String
Dim sFileName As String
Dim ws As Worksheet
Dim myrange
ReDim sheetNameArray(0 To 5) As String
Dim NextWs As Worksheet
Dim PreviousWs As Worksheet
Dim x As Integer
'On Error GoTo Errhandler
Sheets("Settings").Activate
' Retrieve value of 'Period Header' from Settings sheet
Range("C4").Activate
periodName = ActiveCell.Value
' Retrieve value of 'File Name' from Settings sheet
Range("C5").Activate
saveAsName = ActiveCell.Value
' Retrieve value of 'Publish PDF to Folder' from Settings sheet
Range("C6").Activate
WhereTo = ActiveCell.Value
' Check if Stamp-field has any value at all and if not, add the current date.
If Stamp = "" Then Stamp = Date
' Assemble the filename
sFileName = WhereTo & saveAsName & " (" & Format(CDate(Date), "DD-MMM-YYYY") & ").pdf"
Set myrange = Worksheets("Settings").Range("range_sheetProperties")
For Each ws In ActiveWorkbook.Worksheets
printOrder = Application.VLookup(ws.Name, myrange, 4, False)
If Not IsError(printOrder) Then
printOrderNum = printOrder
If printOrderNum <> Empty Then
'Add sheet to array
num = printOrderNum - 1
sheetNameArray(num) = ws.Name
End If
End If
Next
MsgBox Join(sheetNameArray, ",")
'Order Tab sheets based on array
x = 1
Do While Count < 6
If sheetNameArray(x) <> Empty Then
Set PreviousWs = Sheets(sheetNameArray(x - 1))
Set NextWs = Sheets(sheetNameArray(x))
NextWs.Move after:=PreviousWs
x = x + 1
Else
Count = Count + 1
x = x + 1
End If
Loop
Sheets(sheetNameArray).Select
'Save the File as PDF
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:=sFileName, Quality _
:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas:=False, _
OpenAfterPublish:=True
' open the Settings sheet before exiting
Sheets("Settings").Activate
MsgBox "PDF document has been created and saved to : " & sFileName
Exit Sub
Errhandler:
' If an error occurs, unhide and open the Settings sheet then display an error message
Sheets("Settings").Visible = True
Sheets("Settings").Activate
MsgBox "An error has occurred. Please check that the PDF is not already open."
End Sub
You would want to define the worksheets in an array.
This example uses a static array, knowing the sheets order and what you want to print in advance. This does work.
ThisWorkbook.Sheets(Array("Sheet1","Sheet2","Sheet6","Master","Sales")).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, fileName:=sFileName, Quality _
:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas:=False, _
OpenAfterPublish:=True
The problem is that if a sheet is hidden, it will fail on the selection.
So you will need to already know which sheets pass the test to be printed or not before declaring the Array. Therefore you will need a dynamic array to build the list of Worksheets.
I did change how your PrintOrder works, instead of making the sheet invisible, it simply doesn't add it to the array, or vice versa, adds the ones you want to the array. Then you select the array at the end, and run your print macro that works.
I tested this using my own test values, and am trusting that your PrintOrder Test works. But this does work. I used it to print time sheets that only have more than 4 hours per day, and it succeeded, merging 5 sheets out of a workbook with 11 sheets into one PDF.. All of them qualified the test.
TESTED: Insert this instead of your For Each ws and add the Variable Declarations with yours
Sub DynamicSheetArray()
Dim wsArray() As String
Dim ws As Worksheet
Dim wsCount As Long
wsCount = 0
For Each ws In Worksheets
printOrder = Application.VLookup(ws.Name, myrange, 4, False)
If Not IsError(printOrder) Then
If printOrder = "Y" Then
wsCount = wsCount + 1
ReDim Preserve wsArray(1 To wsCount)
'Add sheet to array
wsArray(wsCount) = ws.Name
End If
End If
Next
Sheets(wsArray).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, fileName:=sFileName, Quality _
:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas:=False, _
OpenAfterPublish:=True
End Sub
edit: further explained context of my code to OP
Here is a bit of code I came up with. Basically you would want to take this and adapt it to fit your specific needs but the general idea should work!
Sub MovingPagesAccordingToNumberInRange()
Dim ws As Worksheet
Dim NextWs As Worksheet
Dim PreviousWs As Worksheet
Dim sheetNameArray(0 To 400) As String
Dim i As Integer
'This first loop is taking all of the sheets that have a number
' placed in the specified range (I used Cell A1 of each sheet)
' and it places the name of the worksheet into an array in the
' order that I want the sheets to appear. If I placed a 1 in the cell
' it will move the name to the 1st place in the array (location 0).
' and so on. It only places the name however when there is something
' in that range.
For Each ws In Worksheets
If ws.Cells(1, 1).Value <> Empty Then
num = ws.Cells(1, 1).Value - 1
sheetNameArray(num) = ws.Name
End If
Next
' This next section simply moves the sheets into their
' appropriate positions. It takes the name of the sheets in the
' previous spot in the array and moves the current spot behind that one.
' Since I didn't know how many sheets you would be using I just put
' A counter in the prevent an infinite loop. Basically if the loop encounters 200
' empty spots in the array, everything has probably been organized.
x = 1
Do While Count < 200
If sheetNameArray(x) <> Empty Then
Set PreviousWs = sheets(sheetNameArray(x - 1))
Set NextWs = sheets(sheetNameArray(x))
NextWs.Move after:=PreviousWs
x = x + 1
Else
Count = Count + 1
x = x + 1
End If
Loop
End Sub