I have working VBA code that pulls information from Excel and autofills a Word document.
I want to add another column/bookmark.
I added new bookmarks in the Word template and added the lines:
.BookMarks("CouncilRegion2").Range.Text = Range("W" & r).Value
.BookMarks("CouncilRegion3").Range.Text = Range("X" & r).Value
I get
'Run-time error '5941': The requested member of the collection does not exist.
I did not write the code, I maintain it and add new lines when needed.
I tried changing the Range.
Private Sub CreateTemplate1(tPath As String, r As Integer)
Dim wdApp As Object
Dim wdDoc As Object
On Error Resume Next
Set wdApp = GetObject(, "Word.Application")
If wdApp Is Nothing Then Set wdApp = CreateObject("Word.Application")
On Error GoTo 0
wdApp.Visible = True
'wdApp.DisplayAlerts = False
Set wdDoc = wdApp.Documents.Open(FileName:=tPath)
With wdDoc
.BookMarks("STPNumber").Range.Text = Range("L" & r).Value
.BookMarks("ProposedUse").Range.Text = Range("L" & r).Value
.BookMarks("SiteAddress").Range.Text = Range("E" & r).Value
.BookMarks("LotRp").Range.Text = Range("O" & r).Value
.BookMarks("hSTPNumber").Range.Text = Range("L1").Value
.BookMarks("hSiteAddress").Range.Text = Range("E" & r).Value
.BookMarks("hLotRp").Range.Text = Range("O" & r).Value
.BookMarks("ClientName").Range.Text = Range("C" & r).Value
.BookMarks("ClientName1").Range.Text = Range("C" & r).Value
.BookMarks("TownPlanner").Range.Text = Range("Q" & r).Value
.BookMarks("ProposedUse1").Range.Text = Range("L" & r).Value
.BookMarks("SiteAddress1").Range.Text = Range("E" & r).Value
.BookMarks("CouncilRegion").Range.Text = Range("P" & r).Value
.BookMarks("CurrentDate").Range.Text = Format(Now(), "dd/mm/yyyy")
.BookMarks("CouncilFee").Range.Text = Range("F" & r).Value
.BookMarks("CouncilFee1").Range.Text = Range("F" & r).Value
.BookMarks("hours").Range.Text = Range("K" & r).Value
.BookMarks("hours1").Range.Text = Range("K" & r).Value
.BookMarks("SiteAddress2").Range.Text = Range("E" & r).Value
.BookMarks("ProposedUse2").Range.Text = Range("L" & r).Value
.BookMarks("SiteAddress3").Range.Text = Range("E" & r).Value
.BookMarks("LotRp1").Range.Text = Range("O" & r).Value
.BookMarks("SiteAddress4").Range.Text = Range("E" & r).Value
.BookMarks("LotRp2").Range.Text = Range("O" & r).Value
.BookMarks("ProposedUse3").Range.Text = Range("L" & r).Value
.BookMarks("CouncilRegion2").Range.Text = Range("W" & r).Value
.BookMarks("CouncilRegion3").Range.Text = Range("X" & r).Value
Dim ourFee As Long, ourTotal As Long
Dim ourGST As Long, ourDeposit As Long
ourFee = Range("G" & r).Value
ourGST = ourFee * 0.1
ourTotal = ourFee + ourGST
ourDeposit = ourTotal * 0.6
.BookMarks("OurFeeGST").Range.Text = Format(ourFee, "#,###.00")
.BookMarks("OurFee").Range.Text = Format(ourFee, "#,###.00")
.BookMarks("OurGST").Range.Text = Format(ourGST, "#,###.00")
.BookMarks("OurTotal").Range.Text = Format(ourTotal, "#,###.00")
.BookMarks("OurDeposit").Range.Text = Format(ourDeposit, "#,###.00")
End With
End Sub
The code opens a Word template that is saved in the same folder, and autofills the document using Bookmarks that have been set up.
It won't autofill the lines that I have added and then comes up with the error.
Try printing out all the bookmark names (to the immediate pane in the VB editor) and make sure you see the ones you added:
'...
'...
Set wdDoc = wdApp.Documents.Open(FileName:=tPath)
Dim bm
For Each bm In wdDoc.Bookmarks
Debug.Print bm.Name
Next bm
'...
'...
Related
I found this code to send bulk emails to multiple recipients by Outlook with Excel VBA.
What should I add to it to send two attachments not one?
Sub Send_Multiple_Email()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Sheet3")
Dim oa As Object
Dim msg As Object
Set oa = CreateObject("outlook.Application")
Dim i As Integer
Dim last_row As Integer
last_row = Application.WorksheetFunction.CountA(sh.Range("A:A"))
For i = 2 To last_row
Set msg = oa.createitem(0)
msg.to = sh.Range("A" & i).Value
msg.Subject = sh.Range("B" & i).Value
msg.body = sh.Range("c" & i).Value
If sh.Range("D" & i).Value <> "" Then
msg.attachments.Add sh.Range("D" & i).Value
End If
msg.display
Next i
MsgBox "mails sent"
End Sub
Add information to E2 till the end row and add there what you want to attach like , what is done with D.
And you can add more columns f G H I J K .. with more attachments
If the cell is empty, no attachment is added
If sh.Range("D" & i).Value <> "" Then
msg.attachments.Add sh.Range("D" & i).Value
End If
If sh.Range("E" & i).Value <> "" Then
msg.attachments.Add sh.Range("E" & i).Value
End If
msg.display
Column A contains part numbers such as 499305 and 488212
Sub ProductLoopChemSafe()
Dim X As Integer
Dim lRow As Long
Image1 = 250
Image2 = 500
Image3 = 5000
lRow = Cells(Rows.Count, 1).End(xlUp).Row
For X = 3 To lRow
Range("B" & X).Value = "http://www.chemsafeint.com/images/products/" & Image1 & "/" & Range("A" & X).Value & ".gif"
Range("C" & X).Value = "http://www.chemsafeint.com/images/products/" & Image2 & "/" & Range("A" & X).Value & ".gif"
Range("D" & X).Value = "http://www.chemsafeint.com/images/products/" & Image3 & "/" & Range("A" & X).Value & ".gif"
Range("E" & X).Value = "http://www.chemsafeint.com/files/sds/" & Range("A" & X).Value & ".pdf"
Range("F" & X).Value = "http://www.chemsafeint.com/files/pds/" & Range("A" & X).Value & ".pdf"
Range("G" & X).Value = "http://www.chemsafeint.com/files/idf/" & Range("A" & X).Value & ".pdf"
If Range("A" & X) = "17255" Then
Range("H" & X).Value = "http://www.chemsafeint.com/files/eds/" & Range("A" & X).Value & ".pdf"
End If
If Range("A" & X) = "17418" Then
Range("I" & X).Value = "http://www.chemsafeint.com/files/epp/" & Range("A" & X).Value & ".pdf"
End If
If Range("A" & X) = "17750" Then
Range("I" & X).Value = "http://www.chemsafeint.com/files/epp/" & Range("A" & X).Value & ".pdf"
End If
If Range("A" & X) = "17822" Then
Range("I" & X).Value = "http://www.chemsafeint.com/files/epp/" & Range("A" & X).Value & ".pdf"
End If
Next X
End Sub
How can I test to see if a path is valid before I write it?
I'd like to do something like:
DIM Bvalue as string
Bvalue = "http://www.chemsafeint.com/images/products/" & Image1 & "/" & Range("A" & X).Value & ".gif"
If Bvalue is valid then
Range("B" & X).value = Bvalue
Else
Range("B" & X).value = ""
END IF
You can write a function that receive the URL as parameter and validate it with some web-scraping code then returns true or false if the object of the link is valid. something like isObject( html_element )
The HTML element could be an element that loads everytime when the stuff that you are searching exists. For example the following URL https://chemsafeint.com/images/products/500/11999-DM55.gif has the object img inside the HTML code ( if you are not familiar please search Web Scraping with VBA ), then you can try this:
Function isValid ( byVal URL as string )as boolean
'URL is the link that you have just mounted concatenating strings.
Dim IE As InternetExplorer: Set IE = New InternetExplorer
IE.navigate URL
IE.AddressBar = False
IE.Visible = True
Set IEDOC = IE.document
Dim ELE as HTMLImage
Set ELE = IEDOC.getElementsByTagName("img")
if isObject(ELE) then
isValid = true
else
isValid = false
end if
IE.Quit
Set IE = NOTHING
Exit Function
I created a form to collect data, and during the whole testing Phase the code below was working fine, but all of a sudden it's throwing this error:
This is the code, It was working fine for a while, any idea what might have gone wrong??
Private Sub cmdSave_GotFocus()
Application.ScreenUpdating = False
Dim iRow As Long
iRow = Sheets("Data").Range("A1048576").End(xlUp).Row + 1
If ValidateForm = True Then
With ThisWorkbook.Sheets("Data")
.Range("A" & iRow).Value = iRow - 1
.Range("B" & iRow).Value = txtInitials.Value
.Range("C" & iRow).Value = txtStoreNo.Value
.Range("D" & iRow).Value = cmbLocation.Text
.Range("E" & iRow).Value = IIf(optNew.Value = True, "New", "Existing")
.Range("F" & iRow).Value = txtOpenDate.Value
.Range("G" & iRow).Value = txtRequestDate.Value
.Range("H" & iRow).Value = txtPosition.Value
.Range("I" & iRow).Value = IIf(optFullTime = True, "Full-Time", "Part-Time")
.Range("J" & iRow).Value = TxtNotes.Value
End With
MsgBox ("Submission Successful. Thank You!")
Call Reset
Else
Application.ScreenUpdating = True`enter code here`
End If
Application.ScreenUpdating = True
End Sub
I am trying to add two attachments to an email.
Below is the code I'm using.
My msgbox pops up saying emails sent but the attachments are not attaching.
The paths where I identify where the files live are in columns F & G.
Sub Send_Multiple_Emails_Match45()
Dim sh As Worksheet, Issent As Boolean, i As Long, last_row As Long
Set sh = ThisWorkbook.Sheets("Match 45 Vendors Emails")
Dim OA As Object
Dim msg As Object
Set OA = CreateObject("Outlook.Application")
last_row = sh.Range("B" & Rows.Count).End(xlUp).Row
For i = 4 To last_row
Set msg = OA.createitem(0)
msg.To = sh.Range("B" & i).Value
msg.cc = sh.Range("C" & i).Value
msg.Subject = sh.Range("D" & i).Value
msg.body = sh.Range("E" & i).Value
If sh.Range("F" & "G" & i).Value <> "" Then
If Dir(sh.Range("F" & "G" & i).Value) <> "" Then
msg.Attachments.Add sh.Range("F" & "G" & i).Value
Else
Range("H" & i).Value = "Wrong attachment path"
GoTo NextMail
End If
End If
On Error Resume Next
msg.send
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
Issent = False
Else
On Error GoTo 0
Issent = True
End If
If Issent = True Then
Range("H" & i).Value = "Sent"
Else
Range("H" & i).Value = "Not Sent"
End If
NextMail:
Set msg = Nothing
Next i
MsgBox "Mails Sent"
End Sub
"F:G" & i is incorrect. You need to specify the row for both F and G. The code will not concatenate the two value for you. It would be best to add a helper variable for the filename. This will help make it easier to test your code.
Hi Guys i solve this by adding additional if condition for another attachment. below is my code for you. Enjoy the code
Sub Send_Mails()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Send_Mails")
Dim i As Integer
Dim OA As Object
Dim msg As Object
Set OA = CreateObject("outlook.application")
Dim last_row As Integer
last_row = Application.CountA(sh.Range("A:A"))
For i = 2 To last_row
Set msg = OA.createitem(0)
msg.to = sh.Range("A" & i).Value
msg.cc = sh.Range("B" & i).Value
msg.Subject = sh.Range("C" & i).Value
msg.body = sh.Range("D" & i).Value
If sh.Range("E" & i).Value <> "" Then
msg.attachments.Add sh.Range("E" & i).Value
End If
If sh.Range("F" & i).Value <> "" Then
msg.attachments.Add sh.Range("F" & i).Value
End If
msg.send
sh.Range("g" & i).Value = "Sent"
Next i
MsgBox "All the mails have been sent successfully, Thank u Syed"
End Sub
I figured out the problem, in case in the future anyone needs help with this. This is the updated code where it attaches two files and tells me if each attachment was sent or not sent or there was a wrong path.
Dim sh As Worksheet, Issent As Boolean, i As Long, last_row As Long
Set sh = ThisWorkbook.Sheets("Match 45 Vendors Emails")
Dim OA As Object
Dim msg As Object
Dim rngAttach1 As Range
Dim rngAttach2 As Range
Set OA = CreateObject("Outlook.Application")
last_row = sh.Range("B" & Rows.Count).End(xlUp).Row
Set rngAttach1 = sh.Range("F:F")
Set rngAttach2 = sh.Range("G:G")
For i = 4 To last_row
Set msg = OA.createitem(0)
msg.To = sh.Range("B" & i).Value
msg.cc = sh.Range("C" & i).Value
msg.Subject = sh.Range("D" & i).Value
msg.body = sh.Range("E" & i).Value
If rngAttach1(i).Value <> "" Then
If Dir(rngAttach1(i).Value) <> "" Then
msg.Attachments.Add rngAttach1(i).Value
Else
Range("H" & i).Value = "Wrong attachment path"
GoTo NextMail
End If
End If
If rngAttach2(i).Value <> "" Then
If Dir(rngAttach2(i).Value) <> "" Then
Attachments.Add rngAttach2(i).Value
Else
Range("I" & i).Value = "Wrong attachment path"
GoTo NextMail
End If
End If
On Error Resume Next
msg.send
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
Issent = False
Else
On Error GoTo 0
Issent = True
End If
If Issent = True Then
Range("H" & i).Value = "Sent"
Else
Range("H" & i).Value = "Not Sent"
End If
If Issent = True Then
Range("I" & i).Value = "Sent"
Else
Range("I" & i).Value = "Not Sent"
End If
NextMail:
Set msg = Nothing
Next i
MsgBox "Mails Sent"
End Sub
I have a table in access that I would like to update from excel vba. The new data comes from a saved excel file and each row has an unique ID as their primary key. I would like to make it so that when the new data comes in, any existing entry who's primary key matches that of a new entry will be replaced and any new data that is not replacing an old entry will create a new entry. I believe this is called a left or right join but I am not sure. Currently, my code only adds a new recordset and I can't seem to make it do a join because I am not too familiar with Access vba nor making excel and access talk to each other.
This is my code, which is run from excel:
Function AppendShipment(DatabaseLocation, ExcelFileLocation, dbTableName)
Dim wkb As Excel.Workbook
Dim wks As Excel.Worksheet
Set wkb = Workbooks.Open(ExcelFileLocation)
Set wks = wkb.Worksheets("Sheet1")
Dim strConnection As String
Dim db As Object
Dim rs As Object
Dim r As Integer
Application.ScreenUpdating = False
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" &
DatabaseLocation
Set db = CreateObject("ADODB.Connection")
db.Open strConnection
' open a recordset
Set rs = CreateObject("ADODB.Recordset")
rs.Open dbTableName, db, adOpenKeyset, adLockOptimistic
r = 2 ' the start row in the worksheet
Do While Not Cells(r, 1) = ""
' repeat until first empty cell in column A
With rs
.AddNew ' create a new record
' add values to each field in the record
.Fields("Customer") = Range("A" & r).Value
.Fields("Customer Name") = wks.Range("B" & r).Value
.Fields("Order Date") = wks.Range("C" & r).Value
.Fields("Contract") = wks.Range("D" & r).Value
.Fields("Sales Order") = wks.Range("E" & r).Value
.Fields("Line#") = wks.Range("F" & r).Value
.Fields("Customer Part") = wks.Range("G" & r).Value
.Fields("AFS Part") = wks.Range("H" & r).Value
.Fields("Decription 1") = wks.Range("I" & r).Value
.Fields("Site") = wks.Range("J" & r).Value
.Fields("Product Code") = wks.Range("K" & r).Value
.Fields("Qty Ship") = wks.Range("L" & r).Value
.Fields("Unit Price") = wks.Range("M" & r).Value
.Fields("Customer PO Number") = wks.Range("N" & r).Value
.Fields("Invoice Date") = wks.Range("O" & r).Value
.Fields("Ship Date") = wks.Range("P" & r).Value
.Fields("Ship To") = wks.Range("Q" & r).Value
.Fields("Shipped-Dollars") = wks.Range("R" & r).Value
.Fields("Month1") = wks.Range("S" & r).Value
.Fields("Year1") = wks.Range("Y" & r).Value
.Fields("Product Line") = wks.Range("U" & r).Value
.Fields("Customer Group") = wks.Range("V" & r).Value
.Fields("Customer&Product") = wks.Range("W" & r).Value
.Fields("Customer Group 2") = wks.Range("X" & r).Value
.Fields("Product Subgroup (Type 1)") = wks.Range("Y" & r).Value
.Fields("Product Subgroup (Type 2)") = wks.Range("Z" & r).Value
' add more fields if necessary...
.Update ' stores the new record
End With
r = r + 1 ' next row
Loop
rs.Close
db.Close
ActiveWorkbook.Close SaveChanges:=False
Application.ScreenUpdating = True
End Function
Any helps is appreciated, thank you!
To use a JOIN for an "UPSERT" in MS Access is only possible if the query has access to the source data. In your case, the source data is in Excel and you have to process each single row separately. I suggest to search the unique key in the database to decide whether to add a new record or edit the existing one:
' repeat until first empty cell in column A
With rs
.FindFirst "[Sales Order]=" & wks.Range("E" & r).Value & _
" AND [Line#] = " & wks.Range("F" & r).Value
If .NoMatch Then .AddNew Else .Edit ' create a new or edit existing record
' add values to each field in the record
.Fields....
Since I can't see your data types, I assumed that both [Sales Order] and [Line#] are numbers. If not, you will have to wrap single quotes around the cell values calling the .FindFirst method.
I figured it out!
First, i used .Filter to see if anything matches the current records. If .RecordCount = 0, then nothing matches, so then it does .AddNew. If something does match, it turns out .Edit doesn't work for ADO, instead .MoveFirst needs to be used. Since only 1 recordset will ever match because I am filtering by the primary key and there can be no duplicates, this will edit that recordset no problem.
Function AppendShipment(DatabaseLocation, ExcelFileLocation, dbTableName)
Dim wkb As Excel.Workbook
Dim wks As Excel.Worksheet
Set wkb = Workbooks.Open(ExcelFileLocation)
Set wks = wkb.Worksheets("Sheet1")
Dim strConnection As String
Dim db As Object
Dim rs As Object
Dim r As Integer
Application.ScreenUpdating = False
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & DatabaseLocation
Set db = CreateObject("ADODB.Connection")
db.Open strConnection
' open a recordset
Set rs = CreateObject("ADODB.Recordset")
rs.Open dbTableName, db, adOpenKeyset, adLockOptimistic
r = 2 ' the start row in the worksheet
Do While Not Cells(r, 1) = ""
' repeat until first empty cell in column A
With rs
Debug.Print "[UniqueDB_ID]=" & "'" & Trim(wks.Range("E" & r).Value) &
wks.Range("F" & r).Value & "'"
.Filter = "[UniqueDB_ID]=" & "'" & Trim(wks.Range("E" & r).Value) &
wks.Range("F" & r).Value & "'"
If .RecordCount = 0 Then .AddNew Else .MoveFirst ' create a new record or
edit existing record
' add values to each field in the record
.Fields("UniqueDB_ID") = Trim(wks.Range("E" & r).Value) & wks.Range("F" &
r).Value
.Fields("Customer") = wks.Range("A" & r).Value
.Fields("Customer Name") = wks.Range("B" & r).Value
.Fields("Order Date") = wks.Range("C" & r).Value
.Fields("Contract") = wks.Range("D" & r).Value
.Fields("Sales Order") = Trim(wks.Range("E" & r).Value)
.Fields("Line#") = wks.Range("F" & r).Value
.Fields("Customer Part") = wks.Range("G" & r).Value
.Fields("AFS Part") = wks.Range("H" & r).Value
.Fields("Decription 1") = wks.Range("I" & r).Value
.Fields("Site") = wks.Range("J" & r).Value
.Fields("Product Code") = wks.Range("K" & r).Value
.Fields("Qty Ship") = wks.Range("L" & r).Value
.Fields("Unit Price") = wks.Range("M" & r).Value
.Fields("Customer PO Number") = wks.Range("N" & r).Value
.Fields("Invoice Date") = wks.Range("O" & r).Value
.Fields("Ship Date") = wks.Range("P" & r).Value
.Fields("Ship To") = wks.Range("Q" & r).Value
.Fields("Shipped-Dollars") = wks.Range("R" & r).Value
.Fields("Month1") = wks.Range("S" & r).Value
.Fields("Year1") = wks.Range("Y" & r).Value
.Fields("Product Line") = wks.Range("U" & r).Value
.Fields("Customer Group") = wks.Range("V" & r).Value
.Fields("Customer&Product") = wks.Range("W" & r).Value
.Fields("Customer Group 2") = wks.Range("X" & r).Value
.Fields("Product Subgroup (Type 1)") = wks.Range("Y" & r).Value
.Fields("Product Subgroup (Type 2)") = wks.Range("Z" & r).Value
' add more fields if necessary...
.Update ' stores the new record
End With
r = r + 1 ' next row
Loop
rs.Close
db.Close
ActiveWorkbook.Close SaveChanges:=False
Application.ScreenUpdating = True
End Function
Thank you for your help!