I'm adding an Outlook reminder to run some code. I'd like it to run every two hours.
Below is a sample of one I have that runs every day at the same time. So today, when the Outlook reminder kicks off, it runs some code and then creates a new reminder for two hours from when this one ran.
For example, if this one runs at 7:30 AM, I'd like the new reminder to be created for 9:30 AM and then 11:30 AM, etc.
I'm struggling with the syntax on creating the next reminder. Part of my confusion is when the date changes.
Case "Move Files"
Move_FILES
Call New_Task("Move ENGIE Files", DateAdd("d", 1, Date), " 7:30:00 AM")
vAuto = True
I've used this code for a number of different processes and it has worked for a number of years. The only difference is now it needs to run every two hours.
Sub New_Task(vSubject As String, vDueDate As Date, vTime As String)
Dim myItem As Outlook.TaskItem
Set myItem = Application.CreateItem(olTaskItem)
With myItem
.Subject = vSubject
.DueDate = vDueDate
.ReminderTime = vDueDate & vTime
.Save
DoEvents
.ReminderSet = True
.Save
DoEvents
.ReminderSet = True
DoEvents
.Save
DoEvents
.Close (olSave)
DoEvents
End With
Set myItem = Nothing
End Sub
I was able to resolve my issue by adding a few lines at the beginning of the CASE statement. I added 2 variables and use them to figure out the date and time for the next reminder. Then I pass those 2 variables to the New_Task module. In case anyone wanted to see how I resolved my issue. Thanks...….
Case "Move ENGIE Files"
Dim MyTimer As String
Dim MyDate As Date
vTime = ""
MyTimer = ""
MyDate = 0
MyTimer = CDate(Now)
MyTimer = DateAdd("h", 2, MyTimer)
MyDate = Format(MyTimer, "MM/DD/YYYY")
MyTimer = Format(MyTimer, "HH:MM AM/PM")
MyTimer = " " & MyTimer
Move_Files
Call New_Task("Move ENGIE Files", MyDate, MyTimer)
vAuto = True
Related
I'm trying to figure out how to add a loop that will only create one Outlook calendar event per Markdown End Date.
In my Table Pack Number 6772457 has a shared Markdown End Date date between all my Brand Offers of 2/9/2022 8AM. I'd like to find a way to create only one Entry for all these Brand Offers.
Logically, I'm having an issue figuring out how I would do a loop that would see Multiple Pack numbers on different dates and create event.
Note: The recordset could have multiple pack numbers with different dates and I want to try to make it so each pack number with a date gets a calendar event.
My current code is below.
Any thoughts or push in the right direction would be greatly appreciated!
Pack_Number
Brand Offer
Markdown End Date
6772457
W6
2/9/2022 8:00:00 AM
6772457
V6
2/9/2022 8:00:00 AM
6772457
S6
2/9/2022 8:00:00 AM
6772457
R6
2/9/2022 8:00:00 AM
6772457
P6
2/9/2022 8:00:00 AM
Private Sub Process_InSeason_Click()
Dim olobj As Outlook.Application
Dim oloappt As Outlook.AppointmentItem
Dim myOptionalAttendee As Outlook.Recipient
Dim PackNum As String
Dim rs As Dao.Recordset
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Define objects
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Appt = [Forms]![In Season MD Tracking]![InS_tbl_Original].[Form]![Markdown End Date].Value
Appt = DateSerial(Year(Appt), Month(Appt), Day(Appt))
Appt = Appt + TimeSerial(8, 0, 0)
PackNum = [Forms]![In Season MD Tracking]![InS_tbl_Original].[Form]![Pack_Number].Value
Set rs = CurrentDb.OpenRecordset("InS_tbl_Original")
Set olobj = CreateObject("Outlook.Application")
Set oloappt = olobj.CreateItem(olAppointmentItem)
Set myOptionalAttendee = oloappt.Recipients.Add("")
myOptionalAttendee.Type = olOptional
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Save records and turn on Error Control
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'DoCmd.RunCommand acCmdSaveRecord
On Error GoTo Add_Err
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Validate if Markdown End date is future date
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If rs.Fields("Markdown End Date").Value > Date Then
With oloappt
.RequiredAttendees = myOptionalAttendee
.Subject = "InSeason TEST" 'PackNum & " TEST"
'.Body =
.MeetingStatus = 1
.ResponseRequested = True
.Start = Appt
.Duration = 10
.ReminderSet = True
.ReminderMinutesBeforeStart = 1440
.Save
'.Display
.Send
.Close (olSave)
End With
DoCmd.RunCommand acCmdSaveRecord
MsgBox "Appointment Added!"
Else 'do nothing
End If
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'End process and clean up
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set oloappt = Nothing
Set olobj = Nothing
Exit Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Error validation
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Add_Err:
MsgBox "oops error found " & Err.Number & vbCrLf & Err.Description
Exit Sub
End Sub
I figured it out. In order to make this work I created a query off my table that will remove duplicate pack Numbers. From there I created a look through the records of the query. I want to leave this code active though for anyone who is trying to setup an outlook event through Access. Hopefully this helps!
We are attempting to update the status date in the sub-projects of a Schedule using VBA following the suggestions here and here. Ideally we'd like to keep the files closed while doing so, but are open to suggestions if that isn't strictly possible.
The relevant code looks like this:
If ActiveProject.Subprojects.count > 0 Then
Dim msg: msg = MsgBox("Change Status Date for unopened Subprojects?", vbYesNo, "Change Status Dates for Unopened Subprojects?")
Dim subp As SubProject
If msg = vbYes Then
Application.StatusBar = "Updating Sub-Projects..."
For Each subp In ActiveProject.Subprojects
subp.SourceProject.StatusDate = newDate
subp.SourceProject.SaveAs subp.SourceProject.Name
Next
End If
End If
This appears to work, however when we open the sub-project files the Status Date hasn't changed (as seen on Project > Status > Status Date). The date below is the same before and after:
Alternatives that also have not worked.
We've tried setting Projects(subp.SourceProject.Name).StatusDate:
If ActiveProject.Subprojects.count > 0 Then
Dim msg: msg = MsgBox("Change Status Date for unopened Subprojects?", vbYesNo, "Change Status Dates for Unopened Subprojects?")
Dim subp As SubProject
If msg = vbYes Then
Application.StatusBar = "Updating Sub-Projects..."
For Each subp In ActiveProject.Subprojects
Projects(subp.SourceProject.Name).StatusDate = newDate
subp.SourceProject.SaveAs subp.SourceProject.Name
Next
End If
End If
We've tried to open the sub-projects first and then to change the value (we've tried both FileOpen & FileOpenEx):
If ActiveProject.Subprojects.count > 0 Then
Dim msg: msg = MsgBox("Change Status Date for unopened Subprojects?", vbYesNo, "Change Status Dates for Unopened Subprojects?")
Dim subp As SubProject
If msg = vbYes Then
Application.StatusBar = "Updating Sub-Projects..."
For Each subp In ActiveProject.Subprojects
FileOpen subp.SourceProject.Path
subp.SourceProject.StatusDate = newDate
FileClose pjSave
Next
End If
End If
And then we've tried saving the sub-projects in various ways using:
subp.SourceProject.SaveAs subp.SourceProject.Name
Projects(subp.SourceProject.path).SaveAs subp.SourceProject.Name
As an interesting data point, we do notice that both the SourceProject.StatusDate and Projects(subp.SourceProject.Name).StatusDate for a given sub-project are what we set them to, even if the sub-project, once opened in MSP, does not reflect the value in the interface.
Note: we have tried closing/re-opening and manual save all (user input). No go.
Any suggestions are more than welcome.
EDIT #1
Note that we have also attempted saving the master schedule following the loop using two methods.
First, code leading up to the save:
'save name of Master Schedule to imsProj
dim imsProj as string: imsProj = ActiveProj.Name
If ActiveProject.Subprojects.count > 0 Then
'Here is where we run the above loop
End If
'Ensure the Master Schedule is the active project
Projects(imsProj).Activate
'Master Schedule save goes here. See below.
Then:
Save Method 1
'Save all open Projects, including master
For i = 1 To Projects.count
Projects(i).SaveAs Projects(i).Name
Next i
Save Method 2:
FileSave
Neither works.
Is there a setting in MSP that we are not considering?
Instead of trying to save each subproject individually, save the entire master at the end. Turning of alerts prevents a pop-up confirmation box for each subproject.
Sub SetSubProjectStatusDate()
Dim newDate As Date
newDate = #1/11/2022#
If ActiveProject.Subprojects.Count > 0 Then
Dim msg As VbMsgBoxResult
msg = MsgBox("Change Status Date for unopened Subprojects?", vbYesNo + vbQuestion _
, "Change Status Dates?")
If msg = vbYes Then
Application.StatusBar = "Updating Sub-Projects..."
Dim subp As Subproject
For Each subp In ActiveProject.Subprojects
subp.SourceProject.StatusDate = newDate
Next
DisplayAlerts = False
FileSave
DisplayAlerts = True
End If
End If
End Sub
This is incredibly frustrating, but it appears the IMS and its subprojects were somehow corrupted. No evident cause, no evident effect other than with how the status dates appear. Using a fresh set of MPPs resolved the matter.
Here is the final working code:
If ActiveProject.Subprojects.count > 0 Then
Dim msg: msg = MsgBox("Change Status Date for unopened Subprojects?", vbYesNo, "Change Status Dates for Unopened Subprojects?")
Dim subp As SubProject
If msg = vbYes Then
Application.StatusBar = "Updating Sub-Projects..."
For Each subp In ActiveProject.Subprojects
subp.SourceProject.StatusDate = temp
Next
End If
End If
Projects(imsProj).Activate
FileSave
I admit to being a bit of a novice, but have designed myself a very handy personal MS Access database. I have tried to find a solution to the following on the net, but have been unsuccessful so far, hence my post (the first time I've done this).
I have a marquee on a form in MS Access, which scrolls the count of "incomplete tasks" to do. A "Tasks COUNT Query" provides a number from zero upwards. After the form loads, the code below scrolls a message (right to left) on the marquee in the form "There are X tasks requiring action." X is the number provided from the "Tasks COUNT Query". I would like the text string on the marquee to update on each loop, so that when I mark a task as complete, the next pass on the marquee shows the number (X) as being the updated count.
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim Number As String
Set db = CurrentDb
Set rst = db.OpenRecordset("Tasks COUNT Query")
If Not (rst.EOF And rst.BOF) Then
Do While Not rst.EOF
Number = rst![Tasks]
strTxt = strTxt & "There are " & Number & " tasks requiring action."
rst.MoveNext
Loop
End If
rst.Close
strTxt = Left(strTxt, Len(strTxt)) 'remove the coma at the end
strTxt = Space(30) & strTxt 'start position
Set rst = Nothing
Set db = Nothing
Me.TimerInterval = 180
End Sub
The following code runs on the form timer interval:
Private Sub Form_Timer()
Dim x
On Error GoTo Form_Timer_Err
x = Left(strTxt, 1)
strTxt = Right(strTxt, Len(strTxt) - 1)
strTxt = strTxt & x
lblMarqTask.Caption = Left(strTxt, 180)
Exit Sub
Form_Timer_Exit:
Exit Sub
Form_Timer_Err:
Me.TimerInterval = 0
Exit Sub
End Sub
I would be grateful for any assistance :)
To answer you question: -
I would like the text string on the marquee to update on each loop
To do this you need to place your code that collects the string into its own procedure and then pick a time to call it. I.e.
Move the Form_Load() code into its own procedure
Private Sub GetString()
Dim db As DAO.Database
... [The remaining code] ...
Me.TimerInterval = 180
End Sub
Change Form_Load() to call the new procedure
Private Sub Form_Load()
GetString
End Sub
Have the timer call the new procedure every so often to update the marquee (also known as ticker tape).
Private Sub Form_Timer()
Dim x
Static LngTimes As Long
On Error GoTo Form_Timer_Err
LngTimes = LngTimes + 1
If LngTimes = 100 Then
GetString
LngTimes = 0
End If
x = Left(StrTxt, 1)
StrTxt = Right(StrTxt, Len(StrTxt) - 1)
StrTxt = StrTxt & x
lblMarqTask.Caption = Left(StrTxt, 180)
Exit Sub
Form_Timer_Exit:
Exit Sub
This will update it every 100 times the timer runs. I have tested this and it works, albeit causing a judder in marquee scrolling.
I would like to take the time to give you some extra support in your code that may help understand VBA and make things clearer/easier for you in any future development.
The changes I have supplied are minimal to give you the desired result within the code you have currently. However it does mean I carried some issue across with it. I would perform the same feature with the below: -
Option Compare Database
Option Explicit
Private StrStatus As String
Private Sub GetStatus()
Dim Rs As DAO.Recordset
Set Rs = CurrentDb.OpenRecordset("SELECT count([Task]) FROM [TblTasks] WHERE [Done] = 'No'")
StrStatus = "There are " & Rs(0) & " tasks requiring action."
Rs.Close
Set Rs = Nothing
End Sub
Private Sub Form_Load()
Me.TimerInterval = 180
Me.lblMarqTask.Caption = ""
End Sub
Private Sub Form_Timer()
Static StrStatus_Lcl As String
If StrStatus_Lcl = "" Then
GetStatus
StrStatus_Lcl = StrStatus & Space(30)
If Me.lblMarqTask.Caption = "" Then Me.lblMarqTask.Caption = Space(Len(StrStatus_Lcl))
End If
Me.lblMarqTask.Caption = Right(Me.lblMarqTask.Caption, Len(Me.lblMarqTask.Caption) - 1) & Left(StrStatus_Lcl, 1)
StrStatus_Lcl = Right(StrStatus_Lcl, Len(StrStatus_Lcl) - 1)
End Sub
The result is the string scrolling will remain smooth the value get updates with each iteration.
To talk through what I have done here.
'Option Explicit' Is always good practice to have at the top of your modules/code, it forces you to declare your variables which can save you a headache in the future. This can be automatically added with new code object by enabling 'Require Variable Declaration' in 'Tools' > 'Options' of the VBA Developer environment (also known as the VBE).
Its not clear what the query was doing but to save on a loop I change it to return a single value that I could use. SELECT count([Task]) FROM [TblTasks] WHERE [Done] = 'No' will return a count of all items in TblTasks where the column Done equals No.
In format load I set the timer interval as this only needs setting once and I also ensured the marquee was empty before it run.
The timer keeps a local copy of the status that it remembers. Declaring with the word Static means the content of the variable is not lost between executions in the way a Dim declared variable would be.
If the local copy is empty (i.e. we have used it all up) then update what the status is (GetStatus) and get a new copy.
I hope this has been of help!
I set up the following rules in Outlook 2010...
Apply this rule after the message arrives
from someone#email.com
and with Report in the subject
and which has an attachment
and on this computer only
run Project.ThisOutlookSession.MyScript
The Script is as follows...
Sub methodName(Item As Outlook.MailItem)
Item.Body = "Please find attached"
Item.Save
Dim bolTimeMatch As Boolean
bolTimeMatch = (Time >= #7:00:00 AM#) Or (Time <= #7:30:00 AM#)
If bolTimeMatch Then
Set myForward = Item.Forward
myForward.Recipients.Add "abc#hotmail.com"
myForward.Send
End If
Set myForward = Nothing
End Sub
I would like this particular email to only send daily in the window defined (7:00am - 7:30am)... However it sent the email outside of the window. How could I change the code to only send at that time (UK hours).
First of all, the Outlook object model provides the DeferredDeliveryTime property which can be used to set a Date indicating the date and time the mail message is to be delivered.
Use the logical And operator instead:
bolTimeMatch = (Time >= #7:00:00 AM#) And (Time <= #7:30:00 AM#)
Also you may try to use the TimeValue(Now) instead of Time statements.
Using VBA, I need to show the start date of each INSTANCE of a recurring appointment in Outlook.
The problem is that when I use appt.start it shows the start date of the SERIES, which is not helpful!!
Example: a recurring appointment happens on the first of every month in 2009.
I want to show 12 INSTANCES, with 12 DIFFERENT start dates (1/1/09, 2/1/09, etc).
In other words, all 12 should NOT show start date = 1/1/09.
Thanks
A date restriction will pick up instances of a recurring appointment that occur between the dates specified BUT when you interrogate the properties of the instance - for example .IsRecurring or .AllDayEvent, Outlook redirects the pointer towards the first recurring appointment (the parent as it were). The way round this is to examine the start and end date (copy to local variables) before you lose them by examining other properties.
Dim olNS As Outlook.Namespace
Dim olRec As Outlook.Recipient
Dim myCalItems As Outlook.Items
Dim strRestriction As String
Dim ItemstoCheck As Outlook.Items
Dim MyItem As Outlook.AppointmentItem
Dim datAppStart As Date
Dim datAppEnd As Date
Set myCalItems = olNS.GetSharedDefaultFolder(olRec, olFolderCalendar).Items
' Including recurrent appointments requires sorting by the Start property, apparently!
myCalItems.Sort "[Start]", False
myCalItems.IncludeRecurrences = True
strRestriction = "[Start]<= " & Quote(datEndDate & " 12:00 AM") & " AND [End] >= " & _
Quote(datStartDate & " 11:59 PM")
Set ItemstoCheck = myCalItems.Restrict(strRestriction)
For Each MyItem In ItemstoCheck
If MyItem.Class = olAppointment Then
'Save Start and end dates in case replaced by first instance of recurring appointment
datAppStart = MyItem.Start
datAppEnd = MyItem.End
etc.