If range has specific comment, show msg in another cell - vba

I have this code in VBA and require it to show 'Final Bottling' in another sheet. Below is the code
Ip = input worksheet
op1 = Checks worksheet
i = 1
Cell = Ip.Cells(9, i + 2)
If LCase(Left(Cell, 14)) = "final bottling" Then
'#Checks Final Bottling
Op1.Cells(8, 5) = "Final Bottling Run, Please Consume materials. If unsure, check with materials planner!"
Else
Op1.Cells(8, 5) = ""
End If 'Check
The message appears if all comments in the range C9:H9 have the comment 'Final bottling'. But if only one of the cells in that range has the comment it wont appear anymore.
Not sure what to do now, apologies if this sounds dumb and must be an easy fix

This will show the message if any of the cell in C9:H9 in Ip has "Final bottling"
Sub Test()
Dim i As Long
Dim checkCell As Range
Set checkCell = op1.Cells(8, 5)
For i = 3 To 8
Debug.Print LCase(Left$(Ip.Cells(9, i).Value, 14))
If LCase(Left$(Ip.Cells(9, i).Value, 14)) = "final bottling" Then
checkCell.Value = "Final Bottling Run, Please Consume materials. If unsure, check with materials planner!"
Exit Sub 'Check is complete, exit sub from here
End If
Next i
checkCell.Value = vbNullString 'code will only pass here if it fails all the check in the loop above.
End Sub

You may use Match function to check if the range contains the string and set message:
pos = 0
On Error Resume Next
pos = Application.WorksheetFunction.Match("final bottling", Ip.Range("C9:H9"), 0)
' if not match (case insensitive), then error occurs and pos remains 0; if match was successful, pos = 1+
Op1.Cells(8, 5) = IIf(pos = 0, "", "Final Bottling Run, Please Consume materials. If unsure, check with materials planner!")
On Error GoTo 0
Another way is to use formula like this in cell Opt!E8:
=IFERROR(IF(MATCH("final bottling",Ip!C9:H9,0)>0,"Final Bottling Run, Please Consume materials. If unsure, check with materials
planner!",""),"")
Or use Ip.Range("C9:H9").Find() function

Related

How do I avoid type mismatch in this case?

I'm trying to use a Vlookup function in order to find a copy of a State code on another worksheet. But the range is not matching up with the string. The range is literally just the 50 states and I'm trying to make it match.
I tried checking out to make sure that the state abbreviation was a string. I've also tried converting the range to a string, but that also caused an error. It's strange because if I just match the specific states together, it says that they equal.
Sub State_Assignment()
Application.ScreenUpdating = False
'On Error Resume Next
' State_Assignment Macro
Dim Counter As Integer
Counter = 1
Dim Other As Integer
Other = 0
Dim State As String
State = " "
'
'First, we will check for specialty brokers.
'Check if Specialty Broker requires a state to assign. In this case, we are making sure to include N and n as options, due to future proofing.
If Worksheets("SBSS_Assignment_Tool").Range("G3").Value = "None" Then
ElseIf CStr(Application.VLookup(G3, Worksheets("Special_Cases").Range("A3:A100"), 2)) = "N" Or CStr(Application.VLookup(G3, Worksheets("Special_Cases").Range("A3:A100"), 2)) = "n" Then
E5.Value = WorksheetFunction.VLookup(G3, Worksheets("Special_Cases").Range("A3:A100"), 3)
'If State is needed for Specialty Broker, make sure operator knows. In this case, we are making sure to include Y and y as options, due to future proofing.
ElseIf "Y" = CStr(Application.VLookup(G3, Worksheets("Special_Cases").Range("A3:A100"), 2)) Or "y" = CStr(Application.VLookup(G3, Worksheets("Special_Cases").Range("A3:A100"), 2)) Then
MsgBox ("State is reqired to assign SBSS for this broker.")
'This only leaves the case of Yes and the state is specified.
Else
' Select the cell of the Broker we are looking at.
Worksheets("Special_Cases").Activate
Range("A3:A100").Find(CStr(Application.VLookup(G3, Worksheets("Special_Cases").Range("A3:A100"), 1))).Select
' Now check to make sure the State isn't the cell in the same row as it.
If ActiveCell.Offset(0, 2) = Worksheets("SBSS_Assignment_Tool").Range(G20).Value Then
Worksheets("SBSS_Assignment_Tool").Range(J7).Value = ActiveCell.Offset(0, 3)
'See if there are more states to check, by seeing if there is a empty cell below. We use the Counter varible as future-proofing, so specialty brokers can have as many states as they need.
'The "Other" state specification can also be a problem, so if we see it, we will remeber it's cell and use it if none of the other states match up.
ElseIf ActiveCell.Offset(Counter, 0) = " " Then
If ActiveCell.Offset(Counter, 2) = Worksheets("SBSS_Assignment_Tool").Range(G20).Value Then
Worksheets("SBSS_Assignment_Tool").Range(J7).Value = ActiveCell.Offset(Counter, 3)
ElseIf ActiveCell.Offset(Counter, 2) = "Other" Then
Other = Counter
End If
Counter = Counter + 1
Else
'If we check all the states and none match, we use the "Other" cell.
Worksheets("SBSS_Assignment_Tool").Range(J7).Value = ActiveCell.Offset(Other, 3)
End If
End If
' Looks for State From Drop-Down List and Gather Rules From Cell To The Right of It
Worksheets("SBSS_Assignment_Tool").Range("J20") = Application.VLookup(Worksheets("SBSS_Assignment_Tool").Range("G20").Value, Worksheets("State_Assignments").Range("A2:A100"), 2)
'Check for Special Broker Rules, first ruling out the No's
MsgBox (CStr(Worksheets("SBSS_Assignment_Tool").Range("G20").Value) + " ")
State = Worksheets("SBSS_Assignment_Tool").Range("G20").Value
MsgBox (CStr(Worksheets("State_Assignments").Range("A16").Value) + " ") '
MsgBox (Worksheets("SBSS_Assignment_Tool").Range("G20").Value = Worksheets("State_Assignments").Range("A16").Value)
Dim X As Range
Set X = Worksheets("State_Assignments").Range("A1:A100")
MsgBox (Application.VLookup(State, Worksheets("State_Assignments").Range("A2:A51"), 3))
If Application.VLookup(Worksheets("SBSS_Assignment_Tool").Range("G20").Value, Worksheets("State_Assignments").Range("A1:A100"), 3) = "N" Then
Else
'Selec the cell of the SBSS
Worksheets("Special_Cases").Range("A1:AA1").Find(Application.VLookup(G20, Worksheets("State_Assignments").Range("A1:A100"), 3)).Select
J28.Value = ActiveCell.Offset(1, 0)
End If
The message boxes work, but once it gets the Vlookups is when it starts to flounder.

VBA take screenshot of filtered Excel and send to each row in iteration

I want to run a Macro in Excel to loop through a number of rows, apply a filter to a spreadsheet with the name of the person, take a screenshot, and send an Email to that person with the screenshot.
My current code does not iterate through a range (only 1 record), and does not take a screenshot and insert into email.
Would greatly appreciate assistance with this.
My current code:
Sub SendEmailtoEachResource_Click()
' Macro - Intended functionality
' For each person (resource) apply a filter to the 'Allocation'
' tab, and take a screenshot. Send an email with the screenshot
' to each person.
Dim Resoucename As String
Dim ResouceEmail As String
'Current State: Apply filter, and send 1 email to the below details
ResourceName = Range("D4")
resourceEmail = Range("E4")
'ACTION - Future State:
'For each person in column D
'Send email to email address on same row in Coumn E
' ##Start Loop
'Go to Allocation Tab, Apply Filter of resouce name
Sheets("Allocation").Select
Range("A1:BH28").Select
ActiveSheet.Range("$A$8:$BI$826").AutoFilter Field:=5, Criteria1:= _
ResourceName
ActiveWindow.SmallScroll Down:=-21
ActiveWindow.ScrollRow = 9
Range("A1:BV836").Select
' ACTION: Take Screenshot of filtered results
'setup email
Dim aOutlook As Object
Dim aEmail As Object
Dim outlookResName As String
Dim SendAddress As String
Set aOutlook = CreateObject("Outlook.Application")
Set aEmail = aOutlook.CreateItem(0)
outlookResName = ActiveCell.Value
SendAddress = "me#email.com"
aEmail.To = resourceEmail
aEmail.Subject = "Resource assignment Report for " & ResourceName
aEmail.HTMLBody = "Your report is below {Insert Screenshot}"
'ACTION: Paste screenshot HERE
aEmail.display
' Will change to .send when VBA is working fully. This could send ~100 emails
' ## End LOOP
End Sub
It seems to me that you have two questions rolled up in one here: (1) how to loop through the rows of your spreadsheet and (2) how to take a screenshot and insert it into the e-mail. Maybe you should consider posting two separate questions.
With that in mind, I'll address the loop issue. There are many ways to achieve what you want.
A) You could use the row numbers
For i = 7 To 9
ResourceName = Cells(i, 4)
ResourceEmail = Cells(i, 5)
' The rest of your code here
Next i
B) You could start at the first row and keep moving down until you find an empty cell.
i = 7
Do Until Cells(i, 4) = ""
ResourceName = Cells(i, 4)
ResourceEmail = Cells(i, 5)
' The rest of your code here
i = i + 1
Loop
C) You could give the cells containing the list of resources a name (say, "resources") and loop through its rows.
Set MyList = ActiveWorkbook.Names("resources").RefersToRange
For Each person In MyList.Rows
ResourceName = person.Cells(1, 4)
ResourceEmail = person.Cells(1, 5)
' The rest of your code here
Next person
Why don't you choose one method and then we see where we go from there?

Simple single cell populate with Vlookup value

I am fairly new to VBA, I couldn't really find answer specific to my simple request (most answers were a lot more complicated....). I would like Cell E2 to populate with the result of the vlookup. Is there a simple way to do this?
Thanks and sorry if I failed to find a suitable answer..
Sub vlookup_customerror()
Worksheets("customerror").Activate
On Error GoTo Errormsg
Hobbyquery = Application.WorksheetFunction.VLookup(Range("E1"),
ActiveSheet.Range("A2:B5"), 2, 0)
Cells("E2").Value = Hobbyquery
GoTo ending
Errormsg: GoTo ending
ending: End Sub
Please try This: You can add error handler code also
Sub custom_error()
Dim result As Integer
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets("customerror")
Name = sheet.Range("E1").Value
result = Application.VLookup(Name, sheet.Range("A2:B5"), 2, False)
sheet.Range("E2").Value = result
Debug.Print result
End Sub
If you have string data in Column B then change Dim result As String
EDIT : To cover the situation , if the lookup value is on other sheet as per
apprehension expressed by #MacroMarc. In that case please try This:
Sub custom_error_v2()
Dim result As Variant
On Error Resume Next
result = Application.WorksheetFunction.VLookup(Range("E1"), _
Worksheets("Sheet1").Range("A:C"), 2, False)
On Error GoTo 0
If IsEmpty(result) Then
MsgBox "Value not found!"
End If
Range("E2") = result
End Sub
Images of sample data are appended below.
Please make changes to sheet names as per your requirement.

VBA makro to format XML in Excel to CSV

I need to reformat a XML file to .CSV.
I already opened the XML in Excel and did a little formating but now I really need to write a macro to get the data into shape. I already started bu I really have issues with the loop logic.
the List has a couple thousand Articles with a variable amount of subarticles.
each subarticle as a the same amount of properties but not every article has the same properties.
https://picload.org/image/ipialic/now.jpg
https://picload.org/image/ipialip/then.jpg
My Code up till now looks like this:
Option Explicit
Dim rowCount As Long, articleCount As Long, propertyCount As Integer, name As String
Sub Sortfunction()
rowCount = 1
articleCount = 0
propertyCount = 0
Do While Sheets("Test").Cells(rowCount, 1).Value <> "end"
If Cells(rowCount, 1).Value = "Reference" Then
rowCount = rowCount + 1
Do While Cells(rowCount, 3).Value = ""
If Cells(rowCount, 3).Value = "4" Then
End If
articleCount = articleCount + 1
Loop
articleCount = articleCount + 1
End If
rowCount = rowCount + 1
Loop
Sheets("result").Cells(1, 1).Value = rowCount
Sheets("result").Cells(2, 1).Value = articleCount
End Sub
At the end of the document i wrote the "end" to have a hook to stop the loop.
Can anyone provide some help? I'm really not the best programmer :-/
I'd really appreciate any help I can get :-)
here he's a translation into algorithm and some tips on functions
update: it was more tricky than I thought... I had to rewrite the code.
The main problem is "how to decide when change column".
I choose this solution "Each product in reference must have the same amount of properties".
If it's not the case, please indicate "how you decide when you have to create a new Column" (you can explain it in plain words)
Here the code rewrited. I tried it on your exemple, it work
Public Sub test()
' Set the range to navigate in your first sheet
Dim cell As Range: Set cell = Sheets("Feuil1").Range("A1")
' set the range to navigate in your result sheet
Dim res As Range: Set res = Nothing
' pos will be used to know the position of a product
Dim lastProperties As Range, posProperties As Range
' While the cell value is not "end"
Do While cell <> "end"
' if the cell is a reference
If cell = "Reference" Then
' Set the range of res
If res Is Nothing Then
Set res = Sheets("Feuil2").Range("A1")
Else
Set res = Sheets("Feuil2").Range("A" & lastProperties.offset(2).Row)
End If
' I set Offset(2) so you will have an empty line between 2 references
' Set the text of the new reference in the result
res = cell.offset(, 1) ' The reference is the cell 1 offset the right of the cell "Reference"
' WARNING : here no writing of titles anymore. It'll be done in the "Else".
' Here you just write "new reference" and reinit var
Else
' Here we have a property
' If the property alreay exist, consider it a new product in the reference
' When we are on a new property, the column of the product if the next to the right
If GetProperties(cell.offset(, 3), res, posProperties) Then
Set lastProperties = posProperties
End If
posProperties = cell.offset(, 4)
End If
' BIG FORGET: you have to get the next cell
Set cell = cell.offset(1)
Loop
End Sub
And the function to search / create your properties
Private Function GetProperties(ByVal propValues As String, ByVal start As Range, ByRef position As Range) As Boolean
Set position = start.offset(1)
' Is the cell below the properties ? Return the row below
' Search for the first "empty row" on the line
If position = propValues Then
Do
Set position = position.offset(, 1)
Loop While Trim(position) <> ""
' Indicate it's an existing value
GetProperties = True
Exit Function
End If
' Is the range empty ?
If Trim(position) = "" Then
' Create the new properties
position = propValues
Set position = position.offset(, 1)
GetProperties = False
Exit Function
End If
' Search the properties in the row below
GetProperties = GetProperties(propValues, position, position)
End Function
It should do the work. If you have any question on understanding some part, don't hesitate
if you don't know about Offset, some reading : https://msdn.microsoft.com/en-us/library/office/ff840060.aspx

Skip iteration of loop if certain value exists

I have the following code below that iterates through rows of a specific range and if a value is present (code not seen), creates copies of the entire pages. My concern is at the bottom of the code in the iteration of r1. It originally only had one conditional statement...
If BiDiRowValid(r1)
and I wanted to add a second conditional statement, which I did...
and Range("MAIN_BIDI_PINMC") <> "No BiDi"
but when I run the code and the MAIN_BIDI_PINMC range = "No BiDi", it errors out and doesn't get past that line. FYI: IsBiDiRowValid() is a function that checks to see that the specific r1 is not empty, and then continues. Right after that subroutine finishes and exits, my code errors with a "Type Mismatch error". I also added the ElseIf line at the bottom, I have not gotten to that code because the top errors out, but I just want to make sure I am writing this iteration correctly, and if anything else needs to be done. Basically, if "NoBiDi" is found in the range, I want it to skip all of this code and go to the next r1... which is what I think I have written... Thanks in advance!
Private Sub start_new()
Dim MC_List As Range
Dim r1 As Range
Dim biDiPinName As Range
Dim Pin As String
Dim mc As String
Dim mType As String
Dim tabName As String
Dim rowNumber As Integer
Dim pinmcSplit() As String
Dim NoBidi As String
On Error GoTo start_biDi_tr_new_Error
Set MC_List = Range("MAIN_PINMC_TABLE")
Set biDiPinName = Range("MAIN_PIN2_NAME")
For Each r1 In MC_List.Rows
If IsBiDiRowValid(r1) And WorksheetFunction.CountIf(Worksheets("MAIN").Range("MAIN_BIDI_PINMC", "No Bidi") = 0 Then
tabName = r1.Cells(1, 8)
pinmcSplit = Split(tabName, "_")
Pin = pinmcSplit(0)
mc = pinmcSplit(1)
mType = r1.Cells(1, 3)
ElseIf WorksheetFunction.CountIf(Worksheets("MAIN").Range("MAIN_BIDI_PINMC"), "No Bidi") = 1 Then
End If
Next
You are getting that error because Range("MAIN_BIDI_PINMC") is not a single cell. To check for a value in multiple cells you can use Application.Worksheetfunction.Countif
EDIT
Post discussion in chat, the user wanted to loop through each cell.
Dim aCell As Range
For Each r1 In MC_List.Rows
If IsBiDiRowValid(r1) Then
For Each aCell In Worksheets("MAIN").Range("MAIN_BIDI_PINMC")
If aCell.Value <> "No Bidi" Then
tabName = r1.Cells(1, 8)
pinmcSplit = Split(tabName, "_")
Pin = pinmcSplit(0)
mc = pinmcSplit(1)
mType = r1.Cells(1, 3)
End If
Next
ElseIf aCell.Value = "No Bidi" Then
'~~> Do Something
End If
Next