How to mail merge last row only - excel

I have a couple of excels I am messing around with practicing VBA. They all at have code to mail merge. On one excel I subtract the row number from the row where my headers are. For example my headers are on row 22 and my data starts at row 23. So I subtract 22 from the row number and it begins the mail merge from there (or it only starts to count records from there. I am unsure). So if I have 3 rows of data that would be row 23 to 25. The code subtracts 22 and I am left with 3 records to mail merge. I am learning VBA so I have a hard time figuring out the code I need to only do the last row. Here is my mail merge code:
Private intakeForm As String
Private wdApp As Word.Application
Public newFilePath As String
Public newFolderName As String
Sub MailMergeAutomation()
Dim filePath As String
filePath = ThisWorkbook.Path & "\" & "Forms" & "\"
Dim wdDoc As Word.Document
Dim TargetDoc As Word.Document
Dim recordNumber As Long
Dim selRow As Range
Set selRow = Selection
intakeForm = "New Intake Form"
recordNumber = selRow.Row
Set fso = New Scripting.FileSystemObject
Set wdApp = New Word.Application
If wdApp Is Nothing Then
Set wdApp = New Word.Application
End If
Set fso = New FileSystemObject
With wdApp
.Visible = False
Set wdDoc = .Documents.Open(filePath & intakeForm)
wdDoc.MailMerge.MainDocumentType = wdFormLetters
wdDoc.MailMerge.OpenDataSource _
Name:=ThisWorkbook.Path & "\" & ThisWorkbook.Name, _
AddToRecentFiles:=False, _
Revert:=False, _
Format:=wdOpenFormatAuto, _
Connection:="Data Source=" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & ";Mode=Read", _
SQLStatement:="SELECT * FROM [Headers]"
With wdDoc.MailMerge
.Destination = wdSendToNewDocument
With .DataSource
.FirstRecord = recordNumber - 22
.LastRecord = recordNumber - 22
'.ActiveRecord = .Ac
.LastRecord = recordNumber - 22
End With
.Execute Pause:=False
wdApp.Visible = False
Set TargetDoc = wdApp.ActiveDocument
TargetDoc.SaveAs2 Filename:=ThisWorkbook.Path & "\" & Sheet1.Cells(recordNumber, 3) & " " & "- intakeForm.docx"
wdDoc.Close SaveChanges:=False
End With
End With
Set wdDoc = Nothing
wdApp.Quit
Set wdApp = Nothing
End Sub

The easiest and simplest way to get the last row is usually something like sht.Cells(sht.Rows.Count, "A").End(xlUp).Row and should help you. There are a few other ways of doing it too, so for the record - 5 Different Ways to Find The Last Row or Last Column Using VBA

Related

Edit and save as a PDF in a folder based on Excel information

Im having an issue, I have this Macro to make contracts, it reads the headers on my excel table where I have the information for the contracts (such as Salary, Name, branch offices) and replaces it in a word template.
Also creates a folder with name of the office where the employee works and saves the contratct as PDF with the employee name as filename; because I need to send them to their bosses.
But im having a problem, it does create all the Folders.. but it always ignores the first Branch office (I have them in alphabetical order) and then goes on fine with all the the others.
I ended up creating a new table, create a fake branch office to get the one I need saved.
Can you guys help me find the problem?
Sub CREAR_CARPETAS_X_UNIDAD()
Dim c, lRow As Long
Dim sCarpeta, sContratoModelo, sEmpresa, sNombreApellido, sUnidad As String
Dim sCarpetaUnidad As String
Dim sWord As Object
Dim wb1 As Workbook
Dim WordApp As Word.Application
Dim WordDoc As Object
Application.ScreenUpdating = False
t = Timer
lRow = Cells(Rows.Count, 1).End(xlUp).Row
sCarpeta = Application.ActiveWorkbook.Path
sContratoModelo = sCarpeta & "\CTS_NOVIEMBRE.docx"
'Create Folders for each unit
c = 2
Do
On Error Resume Next
sUnidad = UCase(Range("D" & c).Value)
MkDir sCarpeta & "/" & sUnidad
c = c + 1
Loop While Not c > lRow
'Copy Contract with the client name
Set WordApp = CreateObject("Word.Application")
c = 2
Do
sUnidad = UCase(Range("D" & c).Value)
sNombreApellido = UCase(Range("I" & c).Value)
sCarpetaUnidad = sCarpeta & "/" & sUnidad
WordApp.Visible = True
Set WordDoc = WordApp.Documents.Open(sContratoModelo)
col = 1
Do
With WordDoc.Content.Find
.Text = "OBJ_" & Cells(1, col).Value
.Replacement.Text = Cells(c, col).Value
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
col = col + 1
Loop While Not col > 31
WordDoc.ExportAsFixedFormat OutputFileName:=sCarpetaUnidad & "\" & sNombreApellido & ".pdf", ExportFormat:=wdExportFormatPDF
WordDoc.Close SaveChanges:=wdDoNotSaveChanges
c = c + 1
Loop While Not c > lRow
Application.ScreenUpdating = True
MsgBox ((Timer - t) & " segundos")
End Sub
Are you sure you have a valid folder name for the first Branch office?
Your code could be simplified significantly:
Sub CREAR_CARPETAS_X_UNIDAD()
Application.ScreenUpdating = False
Dim c As Long, t As Single
Dim sCarpeta As String, sContratoModelo As String, sEmpresa As String
Dim sCarpetaUnidad As String, sNombreApellido As String, sUnidad As String
Dim WordApp As Word.Application, WordDoc As Word.Document
t = Timer
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = True
sCarpeta = ActiveWorkbook.Path
sContratoModelo = sCarpeta & "\CTS_NOVIEMBRE.docx"
'Create Folders for each unit
For c = 2 To Cells(Rows.Count, 1).End(xlUp).Row
On Error Resume Next
sUnidad = UCase(Range("D" & c).Value)
MkDir sCarpeta & "/" & sUnidad
'Copy Contract with the client name
sNombreApellido = UCase(Range("I" & c).Value)
sCarpetaUnidad = sCarpeta & "/" & sUnidad
Set WordDoc = WordApp.Documents.Add(sContratoModelo)
With WordDoc
With .Content.Find
.Wrap = wdFindContinue
For col = 1 To 31
.Text = "OBJ_" & Cells(1, col).Value
.Replacement.Text = Cells(c, col).Value
.Execute Replace:=wdReplaceAll
Next
End With
.SaveAs Filename:=sCarpetaUnidad & "\" & sNombreApellido & ".pdf", FileFormat:=wdFormatPDF, AddToRecentFiles:=False
.Close SaveChanges:=wdDoNotSaveChanges
End With
Next
Application.ScreenUpdating = True
MsgBox ((Timer - t) & " segundos")
End Sub
You could also use an automated mailmerge. See Run a Mailmerge from Excel, Sending the Output to Individual Files in the Mailmerge Tips and Tricks page at:
https://www.msofficeforums.com/mail-merge/21803-mailmerge-tips-tricks.html

export from Excel to Word takes very long time on MAC

I have a script that exports specific range of cell from Excel to Word. Below you can see the script
Sub Export_to_Word_Mac()
Dim filename As String
Dim FolderName As String
Dim Folderstring As String
Dim FilePathName As String
Dim sh As Worksheet
Dim print_area As Range
Dim appWD As Object
Dim wddoc As Object
Dim rng As Range
Dim paragraphCount As Long
Set sh = ThisWorkbook.Sheets("Sheet1")
sh.Unprotect
sh.Rows("15:16").EntireRow.Hidden = True
For Each rng In sh.Range("B17:B26")
If rng.Value Like "wpisz zakres usług tutaj..." Then
rng.EntireRow.Hidden = True
Else
rng.EntireRow.Hidden = False
End If
Next rng
sh.Protect
FolderName = "Export"
filename = sh.Range("G4") & "_test_" & Format(Now, "dd-mm-yyyy_hhmm") & ".docx"
Folderstring = CreateFolderinMacOffice2016(NameFolder:=FolderName)
FilePathName = Folderstring & Application.PathSeparator & filename
On Error Resume Next
Set appWD = GetObject(, "Word.application")
If Err = 429 Then
Set appWD = CreateObject("Word.application")
Err.Clear
End If
Set wddoc = appWD.Documents.Add
appWD.Visible = True
With appWD.ActiveDocument.PageSetup
.TopMargin = appWD.InchesToPoints(0.5)
.BottomMargin = appWD.InchesToPoints(0.5)
.LeftMargin = appWD.InchesToPoints(0.5)
.RightMargin = appWD.InchesToPoints(0.5)
End With
'copy range to word
Set print_area = sh.Range("B1:C27")
print_area.Copy
'paste range to Word table
paragraphCount = wddoc.Content.Paragraphs.Count
wddoc.Paragraphs(paragraphCount).Range.Paste
Application.CutCopyMode = False
appWD.ActiveDocument.Tables(1).Rows.Alignment = wdAlignRowCenter
appWD.ActiveDocument.Cells.VerticalAlignment = wdCellAlignVerticalTop
'appWD.Activate
appWD.ActiveDocument.SaveAs (FilePathName)
MsgBox "Plik zostal zapisany jako: " & vbNewLine & filename & vbNewLine & _
" w nowo stworzonym " & FolderName & " w folderze: " & vbNewLine & "Library/Group Containers/UBF8T346G9.Office/"
appWD.Quit
Set wddoc = Nothing
Set appWD = Nothing
End Sub
Function CreateFolderinMacOffice2016(NameFolder As String) As String
Dim OfficeFolder As String
Dim PathToFolder As String
Dim TestStr As String
OfficeFolder = MacScript("return POSIX path of (path to desktop folder) as string")
OfficeFolder = Replace(OfficeFolder, "/Desktop", "") & _
"Library/Group Containers/UBF8T346G9.Office/"
PathToFolder = OfficeFolder & NameFolder
On Error Resume Next
TestStr = Dir(PathToFolder & "*", vbDirectory)
On Error GoTo 0
If TestStr = vbNullString Then
MkDir PathToFolder
'MsgBox "You find the new folder in this location :" & PathToFolder
End If
CreateFolderinMacOffice2016 = PathToFolder
End Function
Unfortunetely, there are a couple of issues:
It takes 1,5-2 minutes to export and save the Word file. Could you please help me to optimize the code?
I need to open Word application on my Mac to run the script. Otherwise I get Run-time error '9' (Script out of Range). The issue is with this line: Set appWD = GetObject(, "Word.application") .
The only solution I came up with is to use .CopyPicture xlScreen and paste it to Word document. I takes arpund 5 second create Word file, however the content is not editable and it is saved as image.
Option 1: Keep using Copy but optimize VBA execution
There are many options to improve speed execution in Excel VBA (see this articles for more details), but the most useful when copy-pasting is certainly to set :
Application.ScreenUpdating = False
However, since you are pasting in Word, you'd have to do the same this for the Word Application to get the maximum speed improvement:
appWD.ScreenUpdating = False
Note: Make sure to reset Application.ScreenUpdating = True at the end of your code.
Option 2 : Use an array to transfer the data
If the formatting of the cell in Excel is not necessary, then you could load the content of the cells into an array and write this array to the word document like this:
'copy range to word
Dim DataArray() As Variant
DataArray = sh.Range("B1:C27").Value
Dim i As Integer, j As Integer
Dim MyWordRange As Object
Set MyRange = appWD.ActiveDocument.Range(0, 0)
appWD.ActiveDocument.Tables.Add Range:=MyRange, NumRows:=UBound(DataArray, 1), NumColumns:=UBound(DataArray, 2)
'paste range to Word table
For i = 1 To UBound(DataArray, 1)
For j = 1 To UBound(DataArray, 2)
appWD.ActiveDocument.Tables(1).Cell(i, j).Range.Text = DataArray(i, j)
Next j
Next i
Note that option 1 and 2 are not necessarily mutually exclusives.

With dic.MailMerge loop wont save my doc.It Starts but it wont stop unless i shut it down

IM trying to crate Microsoft Letters using Excel Data but i cant close the first doc so the loop can go on . I get an Error saying :Excel is Waiting for another Program to close the Oeldb Connection.
I tryed End With after the saving but i get another error saying that there is no other with
//create variables**strong text**
Dim sCurrent_Path As String
Dim recordNumber As Long, totalRecord As Long
sCurrent_Path = ActiveWorkbook.Path
Dim sFull_Path_of_Word_File
sFull_Path_of_Word_File = sCurrent_Path & "\" & sWord_Document_Name
// Start Word
Dim app As Word.Application
Set app = New Word.Application
Dim app As Object
Set app = CreateObject("Word.Application")
app.Visible = False
//Open Word Doc
Dim doc As Word.Document
Set doc = CreateObject("Word.Document")
Set doc = app.Documents.Open(sFull_Path_of_Word_File, ConfirmConversions:=False, ReadOnly:=False, AddToRecentFiles:=False)
Dim wb As Workbook
Set wb = ThisWorkbook
Dim sExcel_Filename As String
sExcel_Filename = ThisWorkbook.FullName
'''
//Loop Start
With doc.MailMerge
.MainDocumentType = wdFormLetters
.OpenDataSource Name:="" & sExcel_Filename & "", ReadOnly:=True,
LinkToSource:=True, Format:=wdOpenFormatAuto,
Connection:="Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;Data
Source=" & sExcel_Filename & ";Mode=Read;Extended
Properties=""HDR=YES;IMEX=1;", SQLStatement:="SELECT * FROM `" &
Table_with_Adresses & "$`", SubType:=wdMergeSubTypeAccess
totalRecord = .DataSource.RecordCount
For recordNumber = 2 To totalRecord
With .DataSource
.ActiveRecord = recordNumber
.FirstRecord = recordNumber
.LastRecord = recordNumber
End With
.Destination = wdSendToNewDocument
.Execute Pause:=False
doc.SaveAs2 sCurrentPath & .DataSource.DataFields("MMID").Value & ".pdf"
//i want to save the document here and then move on to the other data row
doc.Close SaveChanges:=False
Set doc = Nothing
Next recordNumber
End With
Set app = Nothing
I tryed to enter End with after For-Loop but htat didnt work also
Any Ideas?

Excel VBA mail merge with conditions

I am really looking forward to get some help because I am trying for so long now...
I want to get a button in excel that starts a word mailmerge and save every letter as a single document. I already found a code, that is doing this fine.
Now comes the problem: I need excel to take different word templates depending on the number in column A (Column A is called Anz). So if column A = 0 there wont be any mail merge (I already managed this by adding "where (Anz>0) to the sql statement.
If column A = 1 excel shall take sb1.docx as the proper mail merge template.
If column A = 2 it shall take sb2.docx and so on.
The numbers go from 0 to 6.
I have no idea how to to this :(
My code so far (that is working but only for the sb1.docx).
Sub RunMerge()
Application.ScreenUpdating = False
Dim StrMMSrc As String, StrMMDoc As String, StrMMPath As String, StrName As String
Dim i As Long, j As Long
Const StrNoChr As String = """*/\:?|"
Dim wdApp As New Word.Application, wdDoc As Word.Document
wdApp.Visible = False
wdApp.DisplayAlerts = wdAlertsNone
StrMMSrc = ThisWorkbook.FullName
StrMMPath = ThisWorkbook.Path & "\"
StrMMDoc = StrMMPath & "sb1.docx"
Set wdDoc = wdApp.Documents.Open(Filename:=StrMMDoc, AddToRecentFiles:=False, ReadOnly:=True, Visible:=False)
With wdDoc
With .MailMerge
.MainDocumentType = wdFormLetters
.OpenDataSource Name:=StrMMSrc, ReadOnly:=True, AddToRecentFiles:=False, _
LinkToSource:=False, Connection:="Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;" & _
"Data Source=StrMMSrc;Mode=Read;Extended Properties=""HDR=YES;IMEX=1"";", _
SQLStatement:="SELECT * FROM `Sheet1$` where (Anz>0)"
For i = 1 To .DataSource.RecordCount
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
With .DataSource
.FirstRecord = i
.LastRecord = i
.ActiveRecord = i
If Trim(.DataFields("ID")) = "" Then Exit For
StrName = .DataFields("ID")
End With
.Execute Pause:=False
For j = 1 To Len(StrNoChr)
StrName = Replace(StrName, Mid(StrNoChr, j, 1), "_")
Next
StrName = Trim(StrName)
With wdApp.ActiveDocument
.SaveAs Filename:=StrMMPath & StrName & ".docx", FileFormat:=wdFormatXMLDocument, AddToRecentFiles:=False
' and/or:
'.SaveAs Filename:=StrMMPath & StrName & ".pdf", FileFormat:=wdFormatPDF, AddToRecentFiles:=False
.Close SaveChanges:=False
End With
Next i
.MainDocumentType = wdNotAMergeDocument
End With
.Close SaveChanges:=False
End With
wdApp.DisplayAlerts = wdAlertsAll
wdApp.Quit
Set wdDoc = Nothing: Set wdApp = Nothing
Application.ScreenUpdating = False
End Sub
Try this.
Requirements:
- Each Anz number has it's corresponding template
- The excel spreadsheet has a column called "Anz"
- You have to add the Microsoft Word object library to VBA IDE references
Implementation:
1) Copy and paste the code inside a vba module
2) Customize the code (seek for >>>> customize this <<<<)
Updates:
1) Adjusted the queryString
2) Updated the OpenDataSource code to be more clear
3) Added a fileCounter
Code:
' First you have to configure the settings in each template so the word template filters the data already
' Also add a reference in Excel / VBA IDE to: Microsoft Word [Version] Object Library
Public Sub RunMergeDifferentWordTemplates()
' Declare objects
Dim wordApp As Word.Application
Dim wordTemplate As Word.Document
Dim wordMergedDoc As Word.MailMerge
' Declare other variables
Dim sourceBookPath As String
Dim sheetSourceName As String
Dim excelColumnFilter As String
Dim queryString As String
Dim baseQueryString As String
Dim wordTemplateDirectory As String
Dim wordTemplateFileName As String
Dim wordTemplateFullPath As String
Dim wordOutputDirectory As String
Dim wordOutputFileName As String
Dim wordOutputFullPath As String
Dim idListValues As Variant ' Array
Dim idValue As Integer
Dim idCounter As Integer
Dim recordCounter As Integer
Dim fileCounter As Integer
' >>>>> Customize this <<<<<<
' This would be better to hold it in an Excel structured table
' I'm not including 0 as it's not needed (these would correspon to the anz values).
idListValues = Array(1, 2, 3, 4, 5, 6)
' Excel source settings:
sourceBookPath = ThisWorkbook.FullName
sheetSourceName = "Sheet1" ' The sheet where the data of the mail merge is located
excelColumnFilter = "Anz" ' The column we use to filter the mail merge data
baseQueryString = "SELECT * FROM `" & sheetSourceName & "$` where `" & excelColumnFilter & "` = [columFilterValue] order by `" & excelColumnFilter & "` ASC" ' Would be a better practice to use an Excel structured table: https://support.office.com/en-us/article/overview-of-excel-tables-7ab0bb7d-3a9e-4b56-a3c9-6c94334e492c
' Word settings:
wordTemplateDirectory = ThisWorkbook.Path & "\" ' Include slash at the end
wordTemplateFileName = "sb[columFilterValue].docx" ' Include in the string [columFilterValue] where you want it to be replaced (remember that you have one template for each number)
wordOutputDirectory = ThisWorkbook.Path & "\" ' Include slash at the end
wordOutputFileName = "MailMergeDifferent[columFilterValue]_[Record]" ' Leave the [columFilterValue] and [Record] tags inside the path to identify each document. We'll replace it ahead, dynamically
' Initialize word object
Set wordApp = New Word.Application
wordApp.Visible = True
wordApp.DisplayAlerts = wdAlertsNone
' Loop through each idValue in idListValues
For idCounter = 0 To UBound(idListValues)
' Process each word template
idValue = idListValues(idCounter)
queryString = Replace(baseQueryString, "[columFilterValue]", idValue)
wordTemplateFullPath = wordTemplateDirectory & Replace(wordTemplateFileName, "[columFilterValue]", idValue)
Set wordTemplate = wordApp.Documents.Open(wordTemplateFullPath)
Set wordMergedDoc = wordTemplate.MailMerge
' Process the template's mail merge
With wordMergedDoc
.MainDocumentType = wdFormLetters
.OpenDataSource _
Name:=sourceBookPath, _
ReadOnly:=True, _
Format:=wdOpenFormatAuto, _
Revert:=False, _
AddToRecentFiles:=False, _
LinkToSource:=False, _
Connection:="Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;" & _
"Data Source=" & sourceBookPath & ";Mode=Read;Extended Properties=""HDR=YES;IMEX=1"";", _
SQLStatement:=queryString
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
' Each anz have matching records inside the excel worksheet (generate a word file for each one)
For recordCounter = 1 To .DataSource.RecordCount
' Select each record
With .DataSource
.FirstRecord = wordMergedDoc.DataSource.ActiveRecord
.LastRecord = wordMergedDoc.DataSource.ActiveRecord
End With
.Execute Pause:=False
' Add the columnFilterValue and the record identifier to the word file name
' Replace the columnFilterValue and the Record tags
wordOutputFullPath = wordOutputDirectory & Replace(Replace(wordOutputFileName, "[columFilterValue]", idValue), "[Record]", recordCounter)
' Save and close the resulting document
wordApp.ActiveDocument.SaveAs2 Filename:=wordOutputFullPath, FileFormat:=wdFormatXMLDocument, AddToRecentFiles:=False
wordApp.ActiveDocument.SaveAs2 Filename:=wordOutputFullPath, FileFormat:=wdFormatPDF, AddToRecentFiles:=False
wordApp.ActiveDocument.Close SaveChanges:=False
.DataSource.ActiveRecord = wdNextRecord
' Count files generated
fileCounter = fileCounter + 1
Next recordCounter
End With
' Close word template without saving
wordTemplate.Close False
Next idCounter
' Clean up word objects
wordApp.Visible = False
Set wordApp = Nothing
' Alert process finished
MsgBox fileCounter & " files generated"
End Sub

Runtime error 5631

I am trying to generate certificates using the records from my Excel master data file. My coding throws me a VBA error "Runtime error - 5631; Word could not merge the main document with the data source because the data records were empty or no data records matched your query options" every alternate time.
For some data, the code works, whereas for most of the time, it throws error 5631 in the line .Execute Pause:=False
There are records inside the file, so I know there is something wrong with my Query itself.
Other info:
Temp1 = Cookies mailmerge word template,
Temp2 = Chocolates mailmerge word template,
Temp3 = Drinks mailmerge word template
Sheet1 = Cookies sales excel data,
Sheet2 = Chocolates sales excel data,
Sheet3 = Drinks sales excel data
My complete code:
Sub Generate_Cert()
Dim wd As Object
Dim wdoc As Object
Dim i As Integer
Dim isInvalid As Boolean
Dim statement, fileSuffix, datasource As String
Dim aSheet As Worksheet
Dim cDir As String
Dim wdName As String
Const wdFormLetters = 0
Const wdOpenFormatAuto = 0
Const wdSendToNewDocument = 0
Const wdDefaultFirstRecord = 1
Const wdDefaultLastRecord = -16
SalesDate = Format(Worksheets("SalesMaster").Cells(2, "B").Value, "DDMMYYYY")
On Error Resume Next
'Check Word is open or not
Set wd = GetObject(, "Word.Application")
If wd Is Nothing Then
'If Not open, open Word Application
Set wd = CreateObject("Word.Application")
End If
On Error GoTo 0
'Getting datasource
datasource = ThisWorkbook.Path & "\" & ThisWorkbook.Name
'Looping all sheet from workbook
For Each aSheet In ThisWorkbook.Sheets
'If the first cell is not empty
If aSheet.Range("A2").Value <> "" Then
isInvalid = False
'Check sheet for SQLStatement and save file name.
Select Case aSheet.Name
Case "Sheet1"
statement = "SELECT * FROM `Sheet1$`"
fileSuffix = " Cookies Sales"
i = 1
Case "Sheet2"
statement = "SELECT * FROM `Sheet2$`"
fileSuffix = " Chocolates Sales"
i = 2
Case "Sheet3"
statement = "SELECT * FROM `Sheet3$`"
fileSuffix = " Drinks Sales"
i = 3
Case Else
isInvalid = True
End Select
'If sheet should save as word
If Not isInvalid Then
'Getting new word document
Set wdoc = wd.Documents.Open("C:\Desktop\Sales Certs\Temp" & i & ".docx")
With wdoc.MailMerge
.MainDocumentType = wdFormLetters
.OpenDataSource Name:=datasource, AddToRecentFiles:=False, _
Revert:=False, Format:=wdOpenFormatAuto, _
Connection:="Data Source=" & datasource & ";Mode=Read", _
SQLStatement:=statement
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
With .datasource
.FirstRecord = wdDefaultFirstRecord
.LastRecord = wdDefaultLastRecord
End With
.Execute Pause:=False
End With
'wdoc.Visible = True
wdName = SalesDate & fileSuffix & ".docx"
cDir = ActiveWorkbook.Path + "\"
wd.ActiveDocument.SaveAs cDir + wdName
MsgBox SalesDate & fileSuffix & " has been generated and saved"
'wdoc.SaveAs Filename:=wdoc.Name
wdoc.Close SaveChanges:=True
End If
End If
Next aSheet
wd.Quit SaveChanges:=wdDoNotSaveChanges
End Sub
This error was occurring because my source excel document was not saved before the Mailmerge execution. No need to save the word document, as there was no pre-processing necessary before the Mailmerge execution.
So I basically declared wBook as workbook & added this : wBook.Save
Sub Generate_Cert()
Dim wd As Object
Dim wdoc As Object
Dim i As Integer
Dim isInvalid As Boolean
Dim statement, fileSuffix, datasource As String
Dim wBook As Workbook
Dim aSheet As Worksheet
Dim cDir As String
Dim wdName As String
Const wdFormLetters = 0
Const wdOpenFormatAuto = 0
Const wdSendToNewDocument = 0
Const wdDefaultFirstRecord = 1
Const wdDefaultLastRecord = -16
wBook.save '<~~~~~~~ SAVE BEFORE MAILMERGE STARTS
SalesDate = Format(Worksheets("SalesMaster").Cells(2, "B").Value, "DDMMYYYY")
On Error Resume Next
'Check Word is open or not
Set wd = GetObject(, "Word.Application")
If wd Is Nothing Then
'If Not open, open Word Application
Set wd = CreateObject("Word.Application")
End If
On Error GoTo 0
'Getting datasource
datasource = ThisWorkbook.Path & "\" & ThisWorkbook.Name
'Looping all sheet from workbook
For Each aSheet In ThisWorkbook.Sheets
'If the first cell is not empty
If aSheet.Range("A2").Value <> "" Then
isInvalid = False
'Check sheet for SQLStatement and save file name.
Select Case aSheet.Name
Case "Sheet1"
statement = "SELECT * FROM `Sheet1$`"
fileSuffix = " Cookies Sales"
i = 1
Case "Sheet2"
statement = "SELECT * FROM `Sheet2$`"
fileSuffix = " Chocolates Sales"
i = 2
Case "Sheet3"
statement = "SELECT * FROM `Sheet3$`"
fileSuffix = " Drinks Sales"
i = 3
Case Else
isInvalid = True
End Select
'If sheet should save as word
If Not isInvalid Then
'Getting new word document
Set wdoc = wd.Documents.Open("C:\Desktop\Sales Certs\Temp" & i & ".docx")
With wdoc.MailMerge
.MainDocumentType = wdFormLetters
.OpenDataSource Name:=datasource, AddToRecentFiles:=False, _
Revert:=False, Format:=wdOpenFormatAuto, _
Connection:="Data Source=" & datasource & ";Mode=Read", _
SQLStatement:=statement
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
With .datasource
.FirstRecord = wdDefaultFirstRecord
.LastRecord = wdDefaultLastRecord
End With
.Execute Pause:=False
End With
'wdoc.Visible = True
wdName = SalesDate & fileSuffix & ".docx"
cDir = ActiveWorkbook.Path + "\"
wd.ActiveDocument.SaveAs cDir + wdName
MsgBox SalesDate & fileSuffix & " has been generated and saved"
'wdoc.SaveAs Filename:=wdoc.Name
wdoc.Close SaveChanges:=True
End If
End If
Next aSheet
wd.Quit SaveChanges:=wdDoNotSaveChanges
End Sub

Resources