VBA saved workbooks do not open to the last active sheet - excel

I am generating and saving multiple workbooks from another workbook, but when I reopen the saved workbooks the last activated sheet ("Summary") is not active.
I've tried different file formats with the same result. If I pause the code, the Activate command works and if I manually save it from there the Summary sheet is active when opened again. I do not want to save the generated workbooks as macro enabled with an Activate on open.
Sub brandSalesReports()
Set dataWb = ActiveWorkbook
wbPath = Application.ActiveWorkbook.Path
Set macroWb = Workbooks("Macros.xlsm")
macroWb.Activate
Set brandTable = ActiveSheet.ListObjects("BrandTable")
With brandTable.DataBodyRange
tRows = .Rows.Count
End With
dataWb.Activate
ActiveSheet.Name = "Original"
Sheets("Original").Copy Before:=Worksheets("Original")
ActiveSheet.Name = "Data"
LastRow = ActiveSheet.Cells(Rows.Count, 29).End(xlUp).Row 'Get Last Row
Range("AC1").Value = "Brand"
'Fill brand based on Product value
For i = 2 To LastRow
Product = Range("AF" & i).Value
For j = 2 To tRows + 1
Brand = brandTable.Range.Cells(j, 1).Value
If Product Like "*" & Brand & "*" Then
Range("AC" & i).Value = Brand
Exit For
End If
Next j
Next i
LastCol = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
LastColLetter = Split(Cells(1, LastCol).Address, "$")(1)
'Create workbooks for each brand
For k = 2 To tRows + 1
Brand = brandTable.Range.Cells(k, 1).Value
For l = 1 To LastRow
If l = 1 Then
Set currentWb = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
ActiveSheet.Name = "Data"
Set SourceRange = dataWb.Worksheets(1).Range("A1:" & LastColLetter & "1")
Set DestRange = currentWb.Range("A1:" & LastColLetter & "1")
DestRange.Value = SourceRange.Value
Row = 2
dataWb.Activate
ElseIf Range("B" & l).Value = Brand Then
Set SourceRange = dataWb.Worksheets(1).Range("A" & l & ":" & LastColLetter & l)
Set DestRange = currentWb.Range("A" & Row & ":" & LastColLetter & Row)
DestRange.Value = SourceRange.Value
Row = Row + 1
End If
Next l
currentWb.Activate
Worksheets.Add(Before:=Worksheets("Data")).Name = "Summary" 'Add new sheet
LastPivotRow = DSheet.Cells(Rows.Count, 1).End(xlUp).Row
If LastPivotRow <> 1 Then
'PIVOT TABLE CODE HERE, ALL WORKS
Sheets("Summary").Activate
Name = Brand & " Sales Report - " & Format(Date, "mm-dd-yy")
Application.DisplayAlerts = False
currentWb.SaveAs Filename:=wbPath & "\" & Name, FileFormat:=xlOpenXMLWorkbook
End If
ActiveWorkbook.Close
Next k
dataWb.Activate
End Sub

First and foremost, you should try to break your code apart into more well-defined blocks if you can.
Having a sub dedicated to building brand labels, a sub dedicated to creating new workbooks, a sub for writing the pivot tables, one for saving each workbook, and so on will make it easier to debug your code.
I specifically suggest this because breaking up your code into smaller subroutines can let you test less code at once. Therefore you will be able to determine if the issue in your code lies within a specific block, or how those blocks are being chained together (implementation bug vs. integration bug). If you know which block, (or combination of blocks) are causing your issue you can approach debugging in a more targeted manner.
Anyways, looking at your code you are using lots of implicit references. (ex: Range("AC1").Value = "Brand") I would instead urge you to use explicit references (ex: dataWb.Sheets("data").Range("AC1").Value = "Brand"). This is because implicit references are chosen by the computer at runtime, and are not always what you expect them to be. By explicitly stating to use "X" workbook's sheet "Y" we avoid referencing the wrong workbook/worksheet/table/etc.
As an argument to use explicit references, try this minimal example, which correctly saves a file with a summary sheet, and additionally correctly opens to the "summary" sheet.
Sub Test()
Dim wb As Workbook
Set wb = Application.Workbooks.Add()
wb.Activate
wb.Worksheets.Add(Before:=wb.Worksheets("Sheet1")).Name = "Summary"
wb.Sheets("Summary").Activate
wb.SaveAs "Test"
wb.Close (False)
End Sub
If changing your references to be explicit does not solve your issue, I suspect this might be something with your application state. Have you frozen the application before running macros or done anything else?

Related

VBA - lookup in variable workbook

I have a little bit of a problem within an Excel Macro
I have a file populated with huge amount of data extracted from different software and that has to be updated on a monthly basis.
There is data from A2 to O & Lastrow
in column L there is a code that I use to split the sheet into as many sheets as needed (one per existing codes)
Lets say my sheet has 50 lines, the codes present in L are 0250, 40 times and 1225, 10 times so I'll have 2 new sheets
Then all these sheets are saved as individual files for further treatment - and column N of the newly created file will be changed by human
So excel will create a folder and save these 2 sheets as 2 xlsx files according to the month we're in
In my example, it will save them as:
c:\ACCOUNTS\SEP\0250 SEP 19.xlsx
c:\ACCOUNTS\SEP\1225 SEP 19.xlsx
I'm looking for either in the raw extract entirely or at the time the file is split to add in column O a vlookup that will analyze each of these files from the previous month
So I'd like to have a piece of code that will input a Vlookup in the cells, depending of what's in column L of the sheet name to have
=vlookup(A2,c:\ACCOUNTS\AUG\0250 AUG 19.xlsx!A2:O & lastrow,14,0)
or
=vlookup(A2,c:\ACCOUNTS\AUG\1225 AUG 19.xlsx!A2:O & lastrow,14,0)
Sub SPLIT()
Dim main As Worksheet
Dim lastrow As Long
Dim FileExtStr As String
Dim FileFormatNum As Long
Dim xWs As Worksheet
Dim xWb As Workbook
Dim FolderName As String
Set xWb = Application.ThisWorkbook
mBefore = Format(DateAdd("m", -1, Date), "MMM yy")
mPrevious = Format(DateAdd("m", -1, Date), "MMM yy")
Set main = Sheets("Global")
main.Activate
'ActiveSheet.name = "Global"
'Set main = Sheets("Global")
'Calculation of last line
lastrow = main.Cells(Rows.Count, "l").End(xlUp).Row
'MsgBox lastrow
Set FDWDownload1 = Sheets("Global")
Sheets.Add(before:=Sheets("Global")).name = "List"
Set Ref = Sheets("List")
'Creates the table
FDWDownload1.Range("L" & StartPointRow + 1 & ":L" & lastrow).Copy
Ref.Activate
Ref.Range("B2").PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Range("B:B").RemoveDuplicates Columns:=1
Application.CutCopyMode = False
RefLastRow = Ref.Cells(Rows.Count, "B").End(xlUp).Row
FDWDownload1.Activate
If RefLastRow > 0 Then
'For the second row to the end of the table on the References tab
For i = 3 To RefLastRow
'Copy the header from the download
FDWDownload1.Range("A1:P1").Copy
'Add a new sheet placed after the sheet "Global" & name it according to the reference table
Sheets.Add(after:=Sheets("Global")).name = Ref.Range("B" & i)
Set ws = Application.ActiveSheet
'Paste the header into each newly created sheet
ws.Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats
ws.Range("A1").PasteSpecial Paste:=xlPasteFormats
'Get the number of the last row on the newly created sheet
ForLastRow = ws.Cells(Rows.Count, "L").End(xlUp).Row
'As the download is grouped in Product Line order find the first and last row of the Product according to the worksheet name
With FDWDownload1
FDWDownload1.Activate
k = .Range("L:L").Find(what:=ws.name, after:=.Range("L1")).Row
l = .Range("L:L").Find(what:=ws.name, after:=.Range("L1"), searchdirection:=xlPrevious).Row
End With
Range("A" & k & ":O" & l).Copy
ws.Activate
ws.Range("A" & ForLastRow + 1).PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Columns("A:P").EntireColumn.AutoFit
Columns("A:O").AutoFilter
Range("A:O").Sort Key1:=Range("C1"), Order1:=xlAscending, Header:=xlYes
ActiveSheet.name = ws.name & " " & "GRIR" & " " & mBefore
Next i
Else
End If
End Sub
Has the solution to be in VBA? If not you should definetly check out PowerQuery which is included in Excel 2016 and higher. Power Query can do exactly what you asked and doesn't need any code.
Anyway, if I understand you correctly you need to set a formula with VBA.
Try this:
Sub set_formula()
lastrow = 10
Path = "C:\Folder\"
workbookname = "Template.xlsx"
sheetname = "Ids"
Range("D13").Formula = "=VLOOKUP(A2,'" & Path & "[" & workbookname & "]" & sheetname & "'!A2:O" & lastrow & ",14,0)"
End Sub

Copy row of data based on criteria AND "label" that copied data in last column

I have working code that checks for a criteria in each row, and if met, copies that whole row of data over to a different workbook. But! I need to be able to add text to the last column of the copied data (Column S) that essentially labels what criteria was met that made the code copy it over because I will soon be expanding to check for multiple different criteria.
So for every row that meets the criteria and gets copied, I want to add "Criteria1" next to it in column S in the new workbook (it will always be column S that will be the first available column).
I have mangled this code together through inheritance and all of your help, so I don't really even know where to begin.
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Dim CoderBook As Workbook
Dim Referrals As Worksheet
Dim Review As Workbook
Dim Crit As Worksheet
Dim LastRow As Long
Dim NextRow As Long
Dim i As Long
Set CoderBook = Workbooks.Open("Coder Referrals.xlsx")
Set Referrals = CoderBook.Sheets("Sheet1")
Set Review = ThisWorkbook
Set Crit = Review.Sheets("Criteria")
'Search code
LastRow = Crit.Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Application.ScreenUpdating = False
'Loop search code
For i = 2 To LastRow
'Specialized Criteria1 Check
If Crit.Range("F" & i) <> Crit.Range("G" & i) Or _
Crit.Range("I" & i) <> Crit.Range("J" & i) Then
'If meets Criteria1 check, then copy appropriate rows to CoderBook Referrals sheet
Referrals.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).EntireRow.Value = Crit.Rows(i).Value
End If
Next i
'End loop code
CoderBook.Close SaveChanges:=True
Application.ScreenUpdating = True
End Sub
Split the or into two statements:
For i = 2 To LastRow
j = Referrals.Cells(Rows.Count, 1).End(xlUp).row + 1
'Specialized Criteria1 Check
If Crit.Range("F" & i) <> Crit.Range("G" & i) Then
'If meets Criteria1 check, then copy appropriate rows to CoderBook Referrals sheet
Referrals.Rows(j).EntireRow.Value = Crit.Rows(i).Value
Referrals.Range("S" & j).Value = "Criteria1"
End If
If Crit.Range("I" & i) <> Crit.Range("J" & i) Then
Referrals.Rows(j).EntireRow.Value = Crit.Rows(i).Value
if Referrals.Range("S" & j).value = vbNullString then
Referrals.Range("S" & j).Value = "Criteria2"
Else
Referrals.Range("S" & j).Value = Referrals.Range("S" & j).Value & ", " & "Criteria2"
End if
Next i

Update if exist,otherwise insert

I got one situation and I will try to explain it.
I got excel file with two sheets (Sheet 1-Template, Sheet 2-DB). Template is used by manager who appoints yearly targets on monthly base. After state and approve the targets the data will be copy and pasted into DB. But sometimes manager can change targets after approve step.
In this point I need that if the data stated on Template exist on DB, Update, otherwise insert new lines. Actually I wrote code to insert lines but I couldn't write the proper code for check. Please help me on this issue.
Sub MonthlyTargetDB()
Application.ScreenUpdating = False
Dim Target As Workbook: Set Target = ThisWorkbook
Dim Tmpl As Worksheet: Set Tmpl = Target.Worksheets("Template")
Dim DB As Worksheet: Set DB = Target.Worksheets("DB")
Dim i As Integer: i = DB.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Row
Dim j As Integer: j = DB.Range("B" & Rows.Count).End(xlUp).Offset(1, 0).Row
Tmpl.Range("A5").Copy
DB.Range(DB.Range("A" & i), DB.Range("A" & i + 11)).PasteSpecial (xlPasteValues)
Tmpl.Range("B5").Copy
DB.Range(DB.Range("B" & j), DB.Range("B" & j + 11)).PasteSpecial (xlPasteValues)
Tmpl.Range(Tmpl.Range("A8"), Tmpl.Range("B8").End(xlDown)).Copy
DB.Range("C" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial (xlPasteValuesAndNumberFormats)
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub

Excel VBA Macro - Can it be simplified or structured differently?

I made a simple VBA macro that I run against a CSV file that I open in excel. This macro formats the sheet, deletes certain data, inserts columns, etc. It then copies the properly formatted CSV to a server where the data is imported into our ERP. The CSV file is a Bill of Material and everything works great. I am wondering if it could be simplified. When I import this macro as an excel add-in, instead of showing one macro, it shows all the various sub-routines within the macro, along with the main sub that calls all the other subs in the order I need them to run. Is there a better way to arrange this code?
Sub ProcessBOM()
Call DeleteColumn
Call DelBinFill
Call DelBlankRows
Call Insert3Columns
Call DelRow1
Call ClearColumns
Call InsertProjectName
Call InsertLineItemNo
Call InsertEA
Call MoveColumn
Call InsertDate
Call GetUserName
Call SaveAs
Call MessageBox
End Sub
'Delete first column
Sub DeleteColumn()
Columns(1).EntireColumn.Delete
End Sub
'Delete rows containing BIN FILL
Sub DelBinFill()
Dim i As Integer
For i = Cells(Rows.Count, 1).End(xlUp).Row To 1 Step -1
If Cells(i, 1) = "BIN FILL" Then Cells(i, 1).EntireRow.Delete
Next i
End Sub
'Delete rows with blank RDI Item #
Sub DelBlankRows()
Dim i As Integer
For i = Cells(Rows.Count, 1).End(xlUp).Row To 1 Step -1
If Cells(i, 1) = "" Then Cells(i, 1).EntireRow.Delete
Next i
End Sub
'Insert 3 blank columns
Sub Insert3Columns()
Range("A:C").EntireColumn.Insert
End Sub
'Delete Row 1
Sub DelRow1()
Rows(1).EntireRow.Delete
End Sub
'Clear Contents of specified columns
Sub ClearColumns()
Range("E:G").EntireColumn.Clear
End Sub
'Grabs Project Name from Active Sheet and inserts to last row
Sub InsertProjectName()
Dim LastRow As Long
LastRow = Range("D" & Rows.Count).End(xlUp).Row
Range("C1:C" & LastRow) = ActiveSheet.Name
End Sub
'Insert Line Item Numbers
Sub InsertLineItemNo()
ActiveCell.FormulaR1C1 = "1"
LastRow = Range("D" & Rows.Count).End(xlUp).Row
Selection.AutoFill Destination:=Range("A1:A" & LastRow), Type:=xlFillSeries
End Sub
'Insert EA Into Column E
Sub InsertEA()
LastRow = Range("D" & Rows.Count).End(xlUp).Row
Range("E1:E" & LastRow) = "EA"
End Sub
' Moves QTY Data from H to F
Sub MoveColumn()
Columns("H:H").Select
Selection.Cut Destination:=Columns("F:F")
Columns("F:F").Select
End Sub
'Insert Date Into Column G
Sub InsertDate()
Dim LDate As String
LDate = Date
LastRow = Range("D" & Rows.Count).End(xlUp).Row
Range("G1:G" & LastRow).Resize(, 2) = Array(Date, "=""""")
End Sub
'Get logged on username and insert into Column B
Sub GetUserName()
Dim strName As String
strName = Environ("UserName")
LastRow = Range("D" & Rows.Count).End(xlUp).Row
Range("B1:B" & LastRow) = strName
End Sub
'Save file
Sub SaveAs()
Application.DisplayAlerts = False
MyName = ActiveSheet.Name
ActiveWorkbook.SaveAs Filename:="\\navapp1svr\boms$\solidworks\inbound" & "\" & MyName & ".csv", FileFormat:=xlText
ActiveWorkbook.Saved = True
ActiveWorkbook.Close SaveChanges:=False
End Sub
'Prompt the user to verify data upload in Microsoft Dynamics NAV
Sub MessageBox()
MsgBox ("BOM upload complete. Please check Dynamics for accuracy.")
End Sub
I think this is primarily opinion based, but I have a strong opinion here so I'm sharing it. I feel like your code is way over-refactored and there is some extra superfluous stuff in here (variables being set but never used, .SELECT being used to copy/paste, variables declared and set and then only used once)
Consider a single routine:
Sub ProcessBOM()
Dim i As Integer
'Delete first column
Columns(1).EntireColumn.Delete
'Delete rows containing BIN FILL or Nothing
For i = Cells(Rows.Count, 1).End(xlUp).Row To 1 Step -1
If Cells(i, 1) = "BIN FILL" OR Cells(i, 1) = "" Then Cells(i, 1).EntireRow.Delete
Next i
'Insert 3 blank columns
Range("A:C").EntireColumn.Insert
'Delete Row 1
Rows(1).EntireRow.Delete
'Clear Contents of specified columns
Range("E:G").EntireColumn.Clear
'Define last used row
Dim LastRow As Long
LastRow = Range("D" & Rows.Count).End(xlUp).Row
'Grabs Project Name from Active Sheet and inserts to last row
Range("C1:C" & LastRow) = ActiveSheet.Name
'Insert Line Item Numbers
'What is this. How do you know what the "ActiveCell" is at this point or what is "Selected"
'Commenting out because this is risky. Explicitly set which cells you want to do this to
'ActiveCell.FormulaR1C1 = "1"
'Selection.AutoFill Destination:=Range("A1:A" & LastRow),Type:=xlFillSeries
'Insert EA Into Column E
Range("E1:E" & LastRow) = "EA"
' Moves QTY Data from H to F
Columns("H:H").Cut Destination:=Columns("F:F")
'Insert Date Into Column G
Range("G1:G" & LastRow).Resize(, 2) = Array(Date, "=""""")
'Get logged on username and insert into Column B
Range("B1:B" & LastRow) = Environ("UserName")
'Save file
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:="\\navapp1svr\boms$\solidworks\inbound" & "\" & ActiveSheet.Name & ".csv", FileFormat:=xlText
ActiveWorkbook.Saved = True
ActiveWorkbook.Close SaveChanges:=False
'Prompt the user to verify data upload in Microsoft Dynamics NAV
MsgBox ("BOM upload complete. Please check Dynamics for accuracy.")
End Sub
It's only 54 rows including comments and whitespace . In fact, it's only 23 lines of actual code. It's very clear what each step is doing and it can be read by a human without bouncing from the top routine down to whatever step is next. Your getting really close to spaghetti-code and you don't want to go there.
Expanding this out into 15 subroutines doesn't really make sense as they don't really encapsulate much more than a line or two of code and they aren't terribly reusable as they all do a VERY specific thing to a specific range that is only applicable at a single point-in-time while your code is running. If you have more code that may need to reuse some of the code that is present here, then MAYBE consider separating out the logic into it's own subroutine.
There are some pieces that might make sense as their own subroutine or function. For instance you have two routines that are similar DelBinFill and DelBlankRows. These could be written as a single routine with a parameter:
Sub DelRows(criteria As String)
Dim i As Integer
For i = Cells(Rows.Count, 1).End(xlUp).Row To 1 Step -1
If Cells(i, 1) = criteria Then Cells(i, 1).EntireRow.Delete
Next i
End Sub
And called like:
Call DelRows("Bin Fill")
Call DelRows("")
But... now you have to loop through the same range twice and delete rows. It would be MUCH more efficient to loop once (as I do above) and delete based on both criteria.

Use stored value to call or create & call sheet

I have a workbook that creates other workbooks and shifts data to them based on the value in column one. Afterwords I need the workbook to store the data it has just copied in a sheet of the same name as the stored variable (in the next empty row), or create the tab if it does not exist.
However i'm having an issue pasting into the tab with the name of the variable, and no idea how to create a new sheet if the variable does not already exist as a sheet.
It's the With Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste i'm having trouble with.
Current code below. Thanks!
Private Sub CopyItOver()
Dim myVal As String
Dim SupID As String
'Store Supplier ID
SupID = Trim(Sheets("Raw Data").Range("A2").Value)
'Create workbook
Set newbook = Workbooks.Add
'Copy Records
Set myRng = Workbooks("Book1.xlsm").Worksheets("Raw Data").Range("B2:X7")
myRng.Copy
newbook.Worksheets("Sheet1").Range("A2").PasteSpecial (xlPasteValues)
'Create Header
newbook.Worksheets("Sheet1").Range("A1").Value = "ZHF"
newbook.Worksheets("Sheet1").Range("B1").Value = "CTO"
newbook.Worksheets("Sheet1").Range("C1").Value = "RET"
newbook.Worksheets("Sheet1").Range("D1").Value = SupID
newbook.Worksheets("Sheet1").Range("E1").Value = "RET"
newbook.Worksheets("Sheet1").Range("F1").Value = "RET"
newbook.Worksheets("Sheet1").Range("G1").Value = "6"
newbook.Worksheets("Sheet1").Range("H1").Value = "PROD"
newbook.Worksheets("Sheet1").Range("J1").Value = newbook.Worksheets("Sheet1").Range("B1").Value _
& newbook.Worksheets("Sheet1").Range("D1").Value & "TEMPNUMBER"
newbook.Worksheets("Sheet1").Range("I1").Value = newbook.Worksheets("Sheet1").Range("J1").Value _
& newbook.Worksheets("Sheet1").Range("C1").Value & ".CSV"
newbook.Worksheets("Sheet1").Range("K1") = Format(Date, "ddmmyyyy")
newbook.Worksheets("Sheet1").Range("L1").Value = "Unknown"
newbook.Worksheets("Sheet1").Range("M1").Value = "1"
LastRow = newbook.Worksheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row
'Create Footer
newbook.Worksheets("Sheet1").Range("A" & LastRow + 1).Value = "ZFV"
newbook.Worksheets("Sheet1").Range("B" & LastRow + 1).Value = "BATCH" & "TEMPNUMBER"
newbook.Worksheets("Sheet1").Range("C" & LastRow + 1).Value = WorksheetFunction.CountIf(Sheets("Sheet1").Range("A1:A1000"), "RET")
'Name Sheet
myVal = newbook.Worksheets("Sheet1").Range("J1").Value & "RET"
newbook.Worksheets("Sheet1").Name = myVal
'Copy to relevant matching sheet
With Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste
End With
'Save Workbook
NewBook.SaveAs Filename:=NewBook.Worksheets("Sheet1").Range("I1").Value
End Sub
Function DLastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
The error's occurring because Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste is trying to find that worksheet on your active book, ie the new book. You'd need either to Activate your raw data workbook or change the line to ThisWorkbook.Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste.
However, it's not great to use (either explicitly or implicitly) Activate, Select or other keystroke style commands in VBA. Given that you're only copying values (and not the worksheet formats) then, you'd probably be better served reading the data into an array of variants and manipulating those. I've adjusted your code to demonstrate this.
There are some other coding aspects that might not be as robust as they could be. I won't list them all but a comparison of this code with yours will help you see them.
Private Sub CopyItOver()
Dim newBook As Workbook
Dim supSheet As Worksheet
Dim v As Variant
Dim supID As String
Dim namePrefix As String
Dim footerCount As Integer
Dim i As Integer
'Store Supplier ID
supID = Trim(ThisWorkbook.Worksheets("Raw Data").Range("A2").value)
namePrefix = "CTO" & supID & "TEMPNUMBER"
'Create workbook
Set newBook = Workbooks.Add
'Copy Records
v = rawDataSheet.Range("B2:X7").value
For i = 1 To UBound(v, 1)
If v(i, 1) = "RET" Then footerCount = footerCount + 1
Next
'Write new sheet
With newBook.Worksheets(1)
'Values
.Range("A2").Resize(UBound(v, 1), UBound(v, 2)).value = v
'Header
.Range("A1").Resize(, 13) = Array( _
"ZHF", "CTO", "RET", supID, "RET", "RET", "6", "PROD", _
namePrefix & "RET.CSV", namePrefix, _
Format(Date, "ddmmyyyy"), "Unknown", "1")
'Footer
.Cells(.Rows.Count, "A").End(xlUp).Offset(1).Resize(, 3).value = Array( _
"ZFV", "BATCH TEMPNUMBER", footerCount)
'Name
.Name = namePrefix & "RET"
'Save
.SaveAs Filename:=namePrefix & "RET.CSV"
End With
'Copy to relevant matching sheet
On Error Resume Next
Set supSheet = ThisWorkbook.Worksheets(supID)
On Error Goto 0
If newSheet Is Nothing Then
With ThisWorkbook.Worksheets
Set supSheet = .Add(After:=.Item(.Count))
End With
supSheet.Name = supID
End If
With supSheet
.Cells(.Rows.Count, "A").End(xlUp).Offset(1).Resize(UBound(v, 1), UBound(v, 2)).value = v
End With
End Sub
A few things that aren't quite right:
Add Option Explicit at the top of the module and declare your variables.
LastRow will be a Long data type, but you're trying to use it like an array in With Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste. Just use LastRow+1.
With Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste
End With should probably be Worksheets(SupID).Range("A" & LastRow + 1).Paste, but it will paste myRng - can't see anything else you've copied.
At the start of the code you reference Workbooks("Book1.xlsm"). If this is the workbook that the code is in I'd change it to ThisWorkbook.
SupID looks at Raw Data on whichever workbook is active at the time (you'd don't specify the workbook when initialising that variable).
This function will return TRUE/FALSE if a named worksheet exists:
Public Function WorkSheetExists(SheetName As String) As Boolean
Dim wrkSht As Worksheet
On Error Resume Next
Set wrkSht = ThisWorkbook.Worksheets(SheetName)
WorkSheetExists = (Err.Number = 0)
Set wrkSht = Nothing
On Error GoTo 0
End Function
Hope that points you in the right direction :)
Edit:
Just noticed to....
Rather than write:
newbook.Worksheets("Sheet1").Range("A1").Value = "ZHF"
newbook.Worksheets("Sheet1").Range("B1").Value = "CTO"
newbook.Worksheets("Sheet1").Range("C1").Value = "RET"
newbook.Worksheets("Sheet1").Range("D1").Value = SupID
newbook.Worksheets("Sheet1").Range("E1").Value = "RET"
newbook.Worksheets("Sheet1").Range("F1").Value = "RET"
newbook.Worksheets("Sheet1").Range("G1").Value = "6"
newbook.Worksheets("Sheet1").Range("H1").Value = "PROD"
You can just use:
newbook.Worksheets("Sheet1").Range("A1:H1") = Array("ZHF", "CTO", "RET", "SupID", "RET", "RET", "6", "Prod")
I managed to resolve my issue using help from Here, to which I adapted to the code below and ran in a separate module, which allows for the use of a previously unspecified sheet name, that is later derived from a cell value. If the sheet does not exist, it is created matching the name to the stored value and the data pasted into it. Thanks for the support!
Sub TEST()
Dim i As Integer, blnFound As Boolean
blnFound = False
SupID = Trim(Sheets("Raw Data").Range("A2").Value)
Set myRng = Workbooks("Book1.xlsm").Worksheets("Raw Data").Range("B2:X7")
myRng.Copy
With ThisWorkbook
For i = 1 To .Sheets.Count
If .Sheets(i).Name = SupID Then
blnFound = True
.Sheets(i).Activate
ActiveSheet.Paste Destination:=Range("A" & LastRow + 1)
Exit For
End If
Next i
If blnFound = False Then
.Sheets.Add
With ActiveSheet
.Name = SupID
ActiveSheet.Paste Destination:=Range("A" & LastRow + 1)
End With
End If
End With
End Sub

Resources