sum of range amounts realated to the beginning of the month and today date - excel

I wrote this code, but it gives an error. Can you please help me to correct it? I have two columns in excel: one shows the dates (each day, one after another), so that the last date in the column is "yesterday", and the second column shows relevant amounts. I need to write a formula by VBA calculating the sum of those amounts from the beginning of the month till the last row (last date, which is "yesterday"). As you may undertand the beginning of the month changes every month and the last date changes every day. - Thank you very much in advance!
Dim x As Long
x = Month(Workbooks("Reports.xlsm").Worksheets("MACRO").Cells(2, 3))
Range("F64").Formula = "=Sum(" & Range(Cells(Worksheets("A").Cells(Rows.Count, 4).End(xlUp).Row, 4), Cells(Worksheets("A").Cells(Rows.Count, 4).End(xlUp).Row - x, 4))

Yesterday is a Day(Now-1). So:
x = Day(Now-1)-1

Here's a way to find the 1st day of the month and yesterday's rows.
Sub FindYesterdayAnd1stDayofMonth()
' Turn Off screenupdating and calc to speed up code
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Dim wS As Worksheet
Set wS = ActiveSheet
Dim rFound As Range
Dim rS%, rE%
Dim M As Integer, Y As Integer
' Find 1st day of current month
M = Month(Now - 1)
Y = Year(Now - 1)
' Look in column A. Using a Range object to do some error checking when it doesn't work
Set rFound = wS.Columns(1).Find(What:=DateSerial(Y, M, 1), LookIn:=xlValues)
If rFound Is Nothing Then
MsgBox "Date '" & DateSerial(Y, M, 1) & "' not found"
Else
rS = rFound.Row
End If
' Find yesterday
Set rFound = wS.Columns(1).Find(What:=Date - 1, LookIn:=xlValues)
If rFound Is Nothing Then
MsgBox "Date '" & Date - 1 & "' not found"
Else
rE = rFound.Row
End If
' Turn updating and calc back on
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub

Related

How to Test if a Date Falls within a Certain Range and Copy the Entire Row if So Using VBA

I have a file tjhat is serving as a log of product expirations. We track it by two dates, the date as provided by the manufacturer as well as the "Effective Expiration Date". The latter is the date in which the product would expire before someone could use it as directed.
Each year is a separate Worksheet (2022, 2023, 2024, etc.) with a table named after it (_2022, _2023, etc.).
We would like to create a Macro that will go through the the current year's table as well as the one for the next two years searching for a date that falls within the range of today's date through a week later. If it finds a match, the row should be copied over to a new sheet called "Weekly Exp" that is created by the Macro.
So if I ran it today, 12/17/2022, it will search for anything with an Effective Expiration Date between 12/17/2022 and 12/24/2022.
Here is what I have so far:
Sub weeklyExpirationSheet()
Dim dtToday As Date
Dim dtWeekOut As Date
Dim dtEffExp As Date
Dim dtTest As Date
Dim theYear As String
Dim countDays As Long
Dim ws As Worksheet
Dim srcSheet As Worksheet
Dim destSheet As Worksheet
Dim srcTable As ListObject
Dim srcRow As Range
dtToday = Date
dtWeekOut = DateAdd("ww", 1, dtToday)
countDays = DateDiff("d", dtToday, dtWeekOut)
For Each ws In ActiveWorkbook.Worksheets
If ws.Name = "Weekly Exp" Then
MsgBox "Weekly Audit Sheet Already Exists!"
Exit Sub
End If
Next ws
Sheets.Add(After:=Sheets("Incoming")).Name = "Weekly Exp"
Set destSheet = Worksheets("Weekly Exp")
With destSheet
Range("A1").Value = "UPC"
Range("B1").Value = "Brand"
Range("C1").Value = "Product"
Range("D1").Value = "Sz"
Range("E1").Value = "Expr"
Range("F1").Value = "Eff Exp"
Range("G1").Value = "Qty"
Range("H1").Value = "Location"
dtCurrentYear = CDbl(Year(Date))
dtEndYear = CDbl(dtCurrentYear + 2)
For y = dtCurrentYear To dtEndYear
Set srcSheet = Worksheets(CStr(y))
Set srcTable = srcSheet.ListObjects("_" & CStr(y))
With srcSheet
LastRow = .Cells(Rows.Count, "A").End(xlUp).Row
For p = 2 To LastRow
dtTest = .Cells(p, "F").Value
If dtTest >= dtToday And dtTest <= dtWeekOut Then
destLastRow = destSheet.Cells(Rows.Count, "A").End(xlUp).Row + 1
Rows(p).Copy Destination:=destSheet.Rows(destLastRow)
End If
Next p
End With
Next y
End With
End Sub
The code for getting the dates and such is working as is the detection/creation of the Worksheet. However when I run the Macro, it runs for a long period of time (like 3-5min) and then gives a Type Mismatch error. Nothing gets copied.
I did replace the copying code with MsgBox that would just display matches, it was going beyond the range. It reported an item that had a date of 12/31/2022 for example.
Edit:
This is what the data looks like
Your condition is missing the And operator so it always evaluates to True,
Write it like this:
If dtTest >= dtToday And dtTest <= dtWeekOut Then

Excel VBA - compare date in cell to current week

please could someone help me. I have been trying and could not seems to resolve this.
I want to compare the date in Column J to the current week. My code also include finding the last row and automatically loop until the last row.
I currently trying with the following code but having issue with
Recievedate = Format(Cells(i, "J").Value, "ww-yyyy")
I have tried
Recievedate = Format(Range(i, "J").Value, "ww-yyyy")
which was found in another post but it doesn't work. Can someone tell me what have I done wrong please? Please ignore the code after MsgBox "OK" as I am trying to build this step by step. Thank you.
Sub macro1()
Range("A1").Select
Range("A" & Rows.Count).End(xlUp).Select ' Find last row in column A and remember the active cell
Dim i As Integer
Dim Recievedate As Date
For i = 2 To ActiveCell.Row 'start from row 2 and automatically +1 until it reach the active cell
Recievedate = Format(Cells(i, "J").Value, "ww-yyyy")
If Recievedate = Format(Date, "ww-yyyy") Then
MsgBox "OK"
End If
Next i
...
Try
Sub macro1()
Range("A1").Select
Range("A" & Rows.Count).End(xlUp).Select ' Find last row in column A and remember the active cell
Dim i As Integer
' Dim Recievedate As Date
Dim Recievedate As string
For i = 2 To ActiveCell.Row 'start from row 2 and automatically +1 until it reach the active cell
Recievedate = Format(Cells(i, "J").Value, "ww-yyyy")
If Recievedate = Format(Date, "ww-yyyy") Then
MsgBox "OK"
End If
Next i
With this statement Recievedate = Format(Cells(i, "J").Value, "ww-yyyy") you assign a string to Recievedate which cannot work in case Recievedate is declared as date.
Another approach could be to use WorksheetFunction.WeekNum instead.
A possible solution - note, no Selecting required.
Sub Test()
Dim lRow As Long
lRow = Range("A" & Rows.Count).End(xlUp).Row
Dim i As Long
Dim ReceivedDate As Date
For i = 2 To lRow
ReceivedDate = Cells(i, "J")
If Format(ReceivedDate, "ww-yyyy") = Format(Date, "ww-yyyy") Then
MsgBox "Row " & i & " is ok.", vbOKOnly + vbInformation
End If
Next i
End Sub
I suggest you look for a date that is between the start and end dates of the current week.
For example (assuming your week starts on Sunday and ends on the subsequent Saturday)
Sub CurrentWeek()
Dim dt As Date
Dim dtBOW As Date, dtEOW As Date
Dim c As Range, r As Range
dtBOW = Date - Weekday(Date - 1) 'Beginning of week
dtEOW = Date + 7 - Weekday(Date) 'End of week
Set r = ThisWorkbook.Worksheets("Sheet2").Columns(10) 'Column J, fully qualified
For Each c In r.Cells
If c >= dtBOW And c <= dtEOW Then
MsgBox "found it at " & c.Address
c.Select 'Selected only so as to highlight it on the worksheet
Exit Sub
End If
Next c
MsgBox "no luck"
End Sub

Delete date that falls outside of inputted month

I'm creating a sub that formats a new time sheet. I need it to delete dates that fall outside of the inputted month (in this case, June, 2020). The code autofills the next 30 days after the first day, which covers the maximum days in a month (31 days), but also adds date for the first day(s) in the next month if the inputted month has less than 31 days. Here is my code:
Sub Calendar_Genorator3()
Dim WS As Worksheet
Dim MyInput As Variant
Dim StartDay As Variant
Dim DayofWeek As Variant
Dim CurYear As Variant
Dim CurMonth As Variant
Dim FinalDay As Variant
Dim Cell As Range
Dim RowCell As Long
Dim ColCell As Long
Dim Day1 As Range
Set WS = ActiveWorkbook.ActiveSheet
WS.Range("A1:R100").Clear
MyInput = InputBox("Type in Month and year for Calendar ")
If MyInput = "" Then Exit Sub
' Get the date value of the beginning of inputted month.
StartDay = DateValue(MyInput)
' Check if valid date but not the first of the month
' -- if so, reset StartDay to first day of month.
If Day(StartDay) <> 1 Then
StartDay = DateValue(Month(StartDay) & "/1/" & _
Year(StartDay))
End If
'Set headers
Range("a1").Value = Application.Text(MyInput, "mmmm") & " Time Sheet"
Range("a2") = "Day"
Range("c2") = "Time In"
Range("d2") = "Time Out"
Range("e2") = "Hours"
Range("f2") = "Notes"
Range("g2") = "Overtime"
'Set weekdays
Range("a3") = "Sunday"
Range("a4") = "Monday"
Range("a5") = "Tuesday"
Range("a6") = "Wednesday"
Range("a7") = "Thursday"
Range("a8") = "Friday"
Range("a9") = "Saturday"
DayofWeek = Weekday(StartDay)
' Set variables to identify the year and month as separate variables.
CurYear = Year(StartDay)
CurMonth = Month(StartDay)
' Set variable and calculate the first day of the next month.
FinalDay = DateSerial(CurYear, CurMonth + 1, 1)
' Place a "1" in cell position of the first day of the chosen month based on DayofWeek.
Select Case DayofWeek
Case 1
Range("b3").Value = 1
Case 2
Range("b4").Value = 1
Case 3
Range("b5").Value = 1
Case 4
Range("b6").Value = 1
Case 5
Range("b7").Value = 1
Case 6
Range("b8").Value = 1
Case 7
Range("b9").Value = 1
End Select
'Loop through range b3:b44 incrementing each cell after the "1" cell.
For Each Cell In Range("b3:b44")
RowCell = Cell.Row
ColCell = Cell.Column
'Do if "1" is in column B or 2.
If Cell.Row = 1 And Cell.Column = 2 Then
' Do if current cell is not in 1st column.
ElseIf Cell.Row <> 1 Then
If Cell.Offset(-1, 0).Value >= 1 Then
Cell.Value = Cell.Offset(-1, 0).Value + 1
' Stop when the last day of the month has been entered.
If Cell.Value > (FinalDay - StartDay) Then
Cell.Value = ""
' Exit loop when calendar has correct number of days shown.
Exit For
End If
End If
End If
Next
For Each Cell In Range("b3:b9")
If Cell.Value = "" Then
Cell.EntireRow.Clear
End If
Next
'Clears rows without dates
For Each Cell In Range("b3:b9")
If Cell.Value = "" Then
Cell.EntireRow.Delete
End If
Next
'Deletes top rows without dates; needs a loop to successfully delete all empty rows
Range("b2") = "Date"
'Added "Date" in later so date insert works
Set Day1 = WS.Cells.Find(What:="1", LookIn:=xlValues, _
lookat:=xlWhole, searchorder:=xlByColumns, searchdirection:=xlNext, _
MatchCase:=True, SearchFormat:=False)
'Find start day, which is day 1
If Not Day1 Is Nothing Then
Day1.Value = Application.Text(MyInput, "mmm-d")
End If
With Day1
Day1.AutoFill Destination:=Range("B3:B33"), Type:=xlFillDefault
End With
'These final lines of code don't delete ranges with dates that fall outside of the inputted month, because FinalDay doesn't refer to the last day of the month. I need to come up with something that refers to the last day of the month.
FinalDay.Select
With Selection
Cell.Offset(-1).End(xlDown).EntireRow.Delete
End With
End Sub
Here's the output of this code. Any ideas on how to delete the rows that have dates that fall outside of the inputted month? I'm also open to writing this sub an entirely different way; I did it this way because I'm basing it on MS template code.
Yours is a very nice effort. With the code below I have taken a different approach. I hope you will like to study it. I've added lots of comments.
Sub Calendar_Generator()
' 046
Dim Ws As Worksheet
Dim MyInput As String ' InputBox generates a string
Dim StartDay As Date ' this must be date
Dim Sp() As String ' working array
Dim i As Integer ' looping index
Dim R As Long ' row counter
Set Ws = ActiveWorkbook.ActiveSheet ' not a good idea. Always specify the tab by name!
Ws.Range("A1:R100").Clear
Do
MyInput = InputBox("Enter the start date for the Calendar:")
If MyInput = "" Then Exit Sub
Loop While Not IsDate(MyInput) ' repeat if entry isn't recognized as a date
' Set the date value of the beginning of inputted month.
' -- regardless of the day the user entered, even if missing
StartDay = DateSerial(Year(CDate(MyInput)), Month(CDate(MyInput)), 1)
'Set headers
Range("a1").Value = Format(StartDay, "mmmm") & " Time Sheet"
Sp = Split("Day,Date,Time In,Time Out,Hours,Notes,Overtime", ",")
For i = 0 To UBound(Sp)
Ws.Cells(2, 1 + i).Value = Sp(i) ' always specify the worksheet
Next i
' fill the days for the selected month
' == the last day of a month is always the day before the first of the next
' here deducting 2 to count from 0
For R = 0 To Day(DateAdd("m", 1, StartDay) - 2)
With Ws.Cells(3 + R, 2)
.Value = StartDay + R
.NumberFormat = "d-mmm"
.Offset(, -1).Value = StartDay + R
.Offset(, -1).NumberFormat = "dddd"
End With
Next R
End Sub
If you look at the declarations, four out of six - two thirds of their total - are used for code management. That shows where my focus was, and the result is shorter, more efficient code. Much of this was achieved by following a simple rule (which the macro recorder doesn't seem to know): Use cell addressing syntax for addressing cells and range addressing syntax only for addressing ranges of cells. Cell coordinates are easy to calculate and use in loops.

Sumif Returning Same Value

I got below table that I need to fill with data based on current month (Worksheet "PR"):
An example of the raw data looks like (Worksheet "CSV Data PR"):
I have two issues:
SumIF only works for the first region, all the others take the same data. As example, correct data shows below Feb.
For some reason it pulls the formula down all the way..., whilst it should stop at Western Europe. I am not sure why that is the case.
Based on the following piece of code:
Sub TableDataTest()
Dim rngHdrFound, rngHdrFound2, findrng, USDRng, RegionRNG, rngHeaders, RngHeadersOutPut As Range
Dim x, y As Worksheet
Dim ThisMonth As Date
Dim index As Variant
Application.ScreenUpdating = False
'Set Worksheets
Set x = ThisWorkbook.Sheets("CSV Data PR")
Set y = ThisWorkbook.Sheets("PR")
index = y.Range("D8")
ThisMonth = Format(Date, "MM/YYYY")
'Set HeaderRow
Const ROW_HEADERS As Integer = 1
Set rngHeaders = Intersect(Worksheets("CSV Data PR").UsedRange, Worksheets("CSV Data PR").Rows(ROW_HEADERS))
Set RngHeadersOutPut = y.Range("6:6")
Set rngHdrFound = rngHeaders.Find("In USD")
Set rngHdrFound2 = rngHeaders.Find("Region")
Set findrng = RngHeadersOutPut.Find(What:=ThisMonth, LookIn:=xlFormulas, lookat:=xlWhole)
Set USDRng = Range(rngHdrFound.Offset(1), rngHdrFound.End(xlDown))
Set RegionRNG = Range(rngHdrFound2.Offset(1), rngHdrFound2.End(xlDown))
'Find CurrentMonth + Range
With y
If findrng Is Nothing Then
MsgBox "Error, unable to match " & ThisMonth & " in the specified range", vbCritical
Exit Sub
Else
findrng.Offset(2, 0).Resize(Selection.Rows.Count + 8).Value = Application.WorksheetFunction.SumIf(RegionRNG, "=" & index, USDRng)
End If
End With
Application.ScreenUpdating = True
End Sub
You could try this:
Option Explicit
Sub TableDataTest()
Dim ws As Worksheet, wsData As Worksheet, MonthCol As Integer, ThisMonth As Date, C As Range, _
x As Integer, y As Integer
x = 2 'Number of the column with the region
y = 3 'Number of the column with the data to sum
With ThisWorkbook
Set ws = .Sheets("PR")
Set wsData = .Sheets("CSV Data PR")
End With
ThisMonth = Format(wsData.Range("C2"), "MM/YYYY")
With ws
MonthCol = .Cells.Find(ThisMonth, LookIn:=xlFormulas, lookat:=xlWhole).Column
For Each C In .Range(.Cells(3, Col), .Cells(11, Col))
C = Application.SumIf(wsData.Columns(x), .Cells(C.Row, 1), wsData.Columns(y))
Next C
End With
End Sub
You only need to find the column where the month is on the table, and then hardcode the rows you wanna work in because as for I can see, they are always the same and unlikely to grow.
PS: I'm assuming the table starts on row 3 and column A, otherwise change the starting row 3 on the For Each C range and the criteria inside the sumif taking column 1.

execute Worksheet_Change when cell changed by a macro

I have edited this question from initial posting since I realized that no macro will activate the Worksheet_change function.
I am using a UserForm to create a macro to edit a cell. Then I want the Worksheet to take the value from one cell and create values in other cells. This works manually, but not in via macro!
From the UserForm:
Sub WriteOperatingFunds(dates, description, money)
Dim ws2 As Worksheet
Set ws2 = ThisWorkbook.Worksheets("OperatingFunds")
'find first empty row in database
irow = ws2.Cells.Find(What:="*", SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlValues).Row + 1
ws2.Cells(irow, 1).value = dates
ws2.Cells(irow, 2).value = description
ws2.Cells(irow, 3).value = money
End Sub
And from the worksheet:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim change As String
Dim chngRow As Long
Dim IncRow As Long
Dim ExpRow As Long
Dim TotRow As Long
Dim Income As Long
Dim Expense As Long
Dim Total As Long
Set ws = ThisWorkbook.Worksheets("OperatingFunds")
TotRow = ws.Cells(ws.Rows.Count, 5).End(xlUp).Row 'finds bottom of 'Total' Column
'looks for target in range
If Not Application.Intersect(Target, ws.Range("C3", ws.Cells(TotRow + 1, 4))) Is Nothing Then
change = Target.Address(False, False)
chngRow = ws.Range(change).Row
'Get the last rows of range columns
IncRow = ws.Range("C" & ws.Rows.Count).End(xlUp).Row
ExpRow = ws.Range("D" & ws.Rows.Count).End(xlUp).Row
Application.EnableEvents = False 'to prevent endless loop & does not record changes by macro
'if Total column is empty
If ws.Cells(chngRow, 5) = "" Then
Income = Application.WorksheetFunction.Sum(ws.Range("C3", ws.Cells(TotRow + 1, 3)))
Expense = Application.WorksheetFunction.Sum(ws.Range("D3", ws.Cells(TotRow + 1, 4)))
Total = Income + Expense
ws.Cells(chngRow, 5) = Total
'if total column is not empty (i.e. needs to be rewritten)
ElseIf ws.Cells(chngRow, 5) <> "" Then
Income = Application.WorksheetFunction.Sum(ws.Range("C3", ws.Cells(chngRow, 3)))
Expense = Application.WorksheetFunction.Sum(ws.Range("D3", ws.Cells(chngRow, 4)))
Total = Income + Expense
ws.Cells(chngRow, 5) = Total
End If
Else
MsgBox "Else is thrown."
Exit Sub
End If
Application.EnableEvents = True 'so that future changes can be read
End Sub
I don't want to be pretentious to answer my own question, but my friend helped me find the solution, and maybe this will help others with a similar problem.
The key factor is that I'm using a button on UserForm to write data to the cell. It's not actually "changing" the cell when I write "Cells(#,#) = value". In my code, I needed to turn the Sub public and then
Call ThisWorkbook.Worksheets("worksheetname").Worksheet_Change(Target.address)
This made everything work!
His example to help me: https://bytes.com/topic/access/answers/767919-trigger-click-event-button-another-form

Resources