public async Task SendLeaveRequestEmails(LeaveRequest leaveRequest, PersonWithStaff requestedBy, PersonWithStaff toApprove, IEnumerable <PersonWithStaff> toNotify, LeaveUsage leaveUsage) { if (toApprove == null) { throw new UserError( $"Unable to find Supervisor for: {requestedBy.PreferredName} {requestedBy.LastName}"); } await _leaveRequestEmailService.SendRequestApproval(leaveRequest, requestedBy, toApprove, leaveUsage); await Task.WhenAll(toNotify.Where(person => person.Id != toApprove?.Id).Select(supervisor => _leaveRequestEmailService.NotifyOfLeaveRequest(leaveRequest, requestedBy, supervisor, toApprove, leaveUsage))); await _leaveRequestEmailService.NotifyHr(leaveRequest, requestedBy, toApprove, leaveUsage); }
public (PersonWithStaff toApprove, List <PersonWithStaff> toNotify) ResolveLeaveRequestEmails( PersonWithStaff requestedBy) { return(ResolveLeaveRequestEmails(requestedBy, _orgGroupRepository.StaffParentOrgGroups(requestedBy.Staff), _orgGroupRepository.GetOrgGroupsByPersonsRole(requestedBy.Id))); }
public void LeaveListByOrgGroupShouldIncludeChildGroupStaff() { PersonWithStaff rootStaff = null; PersonWithStaff aStaff = null; PersonWithStaff bStaff = null; PersonWithStaff a1Staff = null; var rootGroup = _sf.InsertOrgGroup(action: rootGroupA => { rootStaff = _sf.InsertStaff(rootGroupA.Id); _sf.InsertOrgGroup(rootGroupA.Id, action: aGroupA => { aStaff = _sf.InsertStaff(aGroupA.Id); _sf.InsertOrgGroup(aGroupA.Id, action: a1GroupA => { a1Staff = _sf.InsertStaff(a1GroupA.Id); }); }); _sf.InsertOrgGroup(rootGroupA.Id, action: bGroup => bStaff = _sf.InsertStaff(bGroup.Id)); }); rootStaff.ShouldNotBeNull(); aStaff.ShouldNotBeNull(); bStaff.ShouldNotBeNull(); a1Staff.ShouldNotBeNull(); aStaff.Staff.OrgGroupId.ShouldNotBeNull(); var actualStaff = _leaveService.PeopleInGroupWithLeave(aStaff.Staff.OrgGroupId.Value, DateTime.Now.SchoolYear()); actualStaff.Select(details => details.Person.Id).ShouldBe(new[] { aStaff.Id, a1Staff.Id }, true); actualStaff.Select(details => details.Person.Id).ShouldNotContain(rootStaff.Id); actualStaff.Select(details => details.Person.Id).ShouldNotContain(bStaff.Id); }
private async Task SendRequestApproval(LeaveRequest leaveRequest, PersonWithStaff requestedBy, PersonWithStaff supervisor, LeaveUseage leaveUseage) { //this is a list of substitutions avalible in the email template //these are used when notifying the approving supervisor of leave //$LEAVE-SUBSTITUTIONS$ var substituions = new Dictionary <string, string> { { ":type", leaveRequest.Type.ToString() }, { ":approve", $"{_settings.BaseUrl}/api/leaveRequest/approve/{leaveRequest.Id}" }, { ":firstName", supervisor.PreferredName + " " + supervisor.LastName }, { ":requester", requestedBy.PreferredName + " " + requestedBy.LastName }, { ":start", leaveRequest.StartDate.ToString("MMM d yyyy") }, { ":end", leaveRequest.EndDate.ToString("MMM d yyyy") }, { ":time", $"{leaveRequest.Days} Day(s)" }, { ":left", $"{leaveUseage.Left} Day(s)" } }; await _emailService.SendTemplateEmail(substituions, $"{requestedBy.PreferredName} Leave request approval", EmailTemplate.RequestLeaveApproval, requestedBy, supervisor); }
public static (PersonWithStaff toApprove, List <PersonWithStaff> toNotify) ResolveLeaveRequestEmails( PersonWithStaff requestedBy, IEnumerable <OrgGroupWithSupervisor> approvalGroups, IEnumerable <OrgGroupWithSupervisor> roleGroups) { var supervisorsToNotify = new List <PersonWithStaff>(roleGroups.Select(org => org.SupervisorPerson)); PersonWithStaff toApprove = null; foreach (var orgGroup in OrgGroupService.SortOrgGroupByHierarchy(approvalGroups, OrgGroupService.SortedBy.ChildFirst)) { //super and requested by will be the same if the requester is a supervisor if (orgGroup == null || requestedBy.Id == orgGroup.Supervisor || orgGroup.SupervisorPerson == null) { continue; } if (orgGroup.ApproverIsSupervisor) { toApprove = orgGroup.SupervisorPerson; break; } supervisorsToNotify.Add(orgGroup.SupervisorPerson); } return(toApprove, supervisorsToNotify .Where(toNotify => toNotify.Id != toApprove?.Id && toNotify.Id != requestedBy.Id) .DistinctBy(staff => staff.Id) .ToList()); }
public virtual Task SendTemplateEmail(Dictionary <string, string> substituions, string subject, EmailTemplate emailTemplate, PersonWithStaff @from, IEnumerable <PersonWithStaff> tos) { return(SendTemplateEmail(substituions, subject, emailTemplate, from.Staff.Email, from.PreferredName, tos.Select(person => new EmailAddress(person.Staff.Email, person.PreferredName)).ToList())); }
public IActionResult UpdateSelf([FromBody] PersonWithStaff person) { if (User.PersonId() != person.Id) { throw new UnauthorizedAccessException("You're only allowed to modify your own details "); } _personService.Save(person); return(Json(person)); }
public virtual Task SendTemplateEmail(Dictionary <string, string> substituions, string subject, EmailTemplate emailTemplate, PersonWithStaff @from, PersonWithStaff to) { return(SendTemplateEmail(substituions, subject, emailTemplate, from.Staff.Email, from.PreferredName, to.Staff.Email, to.PreferredName)); }
public async Task <PersonExtended> ResolveLeaveRequestChain(LeaveRequest leaveRequest, PersonWithStaff requestedBy, OrgGroupWithSupervisor department, OrgGroupWithSupervisor devision, OrgGroupWithSupervisor supervisorGroup, LeaveUseage leaveUseage) { return(await DoNotifyWork(leaveRequest, requestedBy, department, leaveUseage) ?? await DoNotifyWork(leaveRequest, requestedBy, devision, leaveUseage) ?? await DoNotifyWork(leaveRequest, requestedBy, supervisorGroup, leaveUseage)); }
public Task NotifyRequestApproved(LeaveRequest leaveRequest, PersonWithStaff requestedBy, PersonWithStaff approvedBy) { var substitutions = BuildSubstitutions(leaveRequest, requestedBy, approvedBy, approvedBy, null); return(_emailService.SendTemplateEmail(substitutions, "Notify leave approved", EmailTemplate.NotifyLeaveApproved, approvedBy, requestedBy)); }
public async Task SendsExpectedEmails(string reason, LeaveRequest request, PersonWithStaff requestedBy, OrgGroupWithSupervisor department, OrgGroupWithSupervisor devision, OrgGroupWithSupervisor supervisorGroup, Guid expectedApproverId, bool expectApprovalEmailSent, int expectedNotifyEmailCount) { bool actualApprovalEmailSent = false; int actualNotifyEmailCount = 0; var emailMock = _servicesFixture.EmailServiceMock.As <IEmailService>(); emailMock.Setup(service => service.SendTemplateEmail(It.IsAny <Dictionary <string, string> >(), It.IsAny <string>(), It.IsAny <EmailTemplate>(), It.IsAny <PersonWithStaff>(), It.IsAny <PersonWithStaff>())) .Returns(Task.CompletedTask) .Callback <Dictionary <string, string>, string, EmailTemplate, PersonWithStaff, PersonWithStaff>( (dictionary, subject, template, to, from) => { if (template == EmailTemplate.RequestLeaveApproval) { actualApprovalEmailSent = true; } else if (template == EmailTemplate.NotifyLeaveRequest) { actualNotifyEmailCount++; } }); var actualApprover = await _leaveService.ResolveLeaveRequestChain(request, requestedBy, department, devision, supervisorGroup, new LeaveUseage() { LeaveType = LeaveType.Sick, TotalAllowed = 20, Used = 0 }); Assert.True((expectedApproverId == Guid.Empty) == (actualApprover == null)); if (actualApprover != null) { Assert.Equal(expectedApproverId, actualApprover.Id); } Assert.Equal(expectApprovalEmailSent, actualApprovalEmailSent); Assert.Equal(expectedNotifyEmailCount, actualNotifyEmailCount); }
public Task SendRequestApproval(LeaveRequest leaveRequest, PersonWithStaff requestedBy, PersonWithStaff supervisor, LeaveUsage leaveUsage) { var substitutions = BuildSubstitutions(leaveRequest, requestedBy, supervisor, supervisor, leaveUsage); return(_emailService.SendTemplateEmail(substitutions, $"{PersonFullName(requestedBy)} Leave request approval", EmailTemplate.RequestLeaveApproval, requestedBy, supervisor)); }
public async Task NotifyOfLeaveRequest(LeaveRequest leaveRequest, PersonWithStaff requestedBy, PersonWithStaff supervisor, PersonWithStaff approver, LeaveUsage leaveUsage) { var substitutions = BuildSubstitutions(leaveRequest, requestedBy, supervisor, approver, leaveUsage); await _emailService.SendTemplateEmail(substitutions, $"{PersonFullName(requestedBy)} has requested leave", EmailTemplate.NotifyLeaveRequest, requestedBy, supervisor); }
public void EnsureAllLeaveCalculatesUseTheSameDateRanges(PersonWithStaff person, ICollection <LeaveRequest> requests, int size) { _sf.DbConnection.Insert(person); _sf.DbConnection.Insert <Staff>(person.Staff); _sf.DbConnection.BulkCopy(requests); var leaveUsages = WaysToGetVacationLeaveCalculation(person.Id, 2017, _sf.Get <LeaveService>()); leaveUsages.ShouldAllBe(used => leaveUsages.First().Used == used.Used, () => $"Window at {requests.First().StartDate.ToShortDateString()} Size: {size}, Requests: [{string.Join(", ", requests)}]"); }
public async Task NotifyHr(LeaveRequest leaveRequest, PersonWithStaff requestedBy, PersonExtended supervisor, LeaveUsage leaveUsage) { if (!ShouldNotifyHr(leaveRequest, leaveUsage)) { return; } var substitutions = BuildSubstitutions(leaveRequest, requestedBy, supervisor, supervisor, leaveUsage); await _emailService.SendTemplateEmail(substitutions, $"{PersonFullName(requestedBy)} has requested leave", EmailTemplate.NotifyHrLeaveRequest, requestedBy, _personRepository.GetStaffNotifyHr()); }
public void Save(PersonWithStaff person) { if (string.IsNullOrEmpty(person.PreferredName)) { person.PreferredName = person.FirstName; } if (person.Staff != null) { _entityService.Save <Staff>(person.Staff); person.StaffId = person.Staff.Id; } else { if (person.StaffId.HasValue) { _personRepository.DeleteStaff(person.StaffId.Value); } person.StaffId = null; } _entityService.Save <PersonExtended>(person); if (person.Staff != null) { MatchStaffWithUser(person.Staff, person.Id); } if (person.SpouseChanged) { if (person.SpouseId.HasValue) { //find the spouse and set them to be this persons spouse _personRepository.PeopleExtended.Where(extended => extended.Id == person.SpouseId) .Set(extended => extended.SpouseId, person.Id).Update(); //note at the moment you could orphan a spouse this way, in the future we could write another update //so to set anyone who has this person as a spouse to null, this would only happen //if you changed someone from the spouse of one person to another though } else { //find the current spouse and make them not spouses anymore _personRepository.PeopleExtended.Where(extended => extended.SpouseId == person.Id) .Set(extended => extended.SpouseId, (Guid?)null).Update(); } } }
public async Task SendsExpectedEmails(string reason, LeaveRequest request, PersonWithStaff requestedBy, PersonWithStaff toApprove, List <PersonWithStaff> toNotify, bool expectApprovalEmailSent, int expectedNotifyEmailCount) { var leaveService = _scopeServiceProvider.GetService <LeaveService>(); bool actualApprovalEmailSent = false; int actualNotifyEmailCount = 0; _sf.GetScopedMockEmailService(_serviceScope) .Setup(service => service.SendTemplateEmail(It.IsAny <Dictionary <string, string> >(), It.IsAny <string>(), It.IsAny <EmailTemplate>(), It.IsAny <PersonWithStaff>(), It.IsAny <PersonWithStaff>())) .Returns(Task.CompletedTask) .Callback <Dictionary <string, string>, string, EmailTemplate, PersonWithStaff, PersonWithStaff>( (dictionary, subject, template, from, to) => { if (template == EmailTemplate.RequestLeaveApproval) { actualApprovalEmailSent = true; } else if (template == EmailTemplate.NotifyLeaveRequest) { actualNotifyEmailCount++; } }); await leaveService.SendLeaveRequestEmails(request, requestedBy, toApprove, toNotify, new LeaveUsage { LeaveType = LeaveType.Sick, TotalAllowed = 20, Used = 0 }); actualApprovalEmailSent.ShouldBe(expectApprovalEmailSent, reason); actualNotifyEmailCount.ShouldBe(expectedNotifyEmailCount, reason); }
public void NotifiesHrWhenAppropriate(LeaveRequest request, PersonWithStaff personWithStaff, int usedLeave, int totalYears, bool expectedEmailed) { var job = _servicesFixture.InsertJob(j => { //force job to provide time off j.Type = JobType.FullTime; j.OrgGroup.Type = GroupType.Department; }); _dbConnection.Insert(personWithStaff); _dbConnection.Insert(personWithStaff.Staff); //create roles for # of years _servicesFixture.InsertRole(job.Id, personWithStaff.Id, totalYears); //insert used leave _servicesFixture.InsertLeaveRequest(request.Type, personWithStaff.Id, usedLeave); var actualEmailed = _leaveService.ShouldNotifyHr(request, _leaveService.GetCurrentLeaveUseage(request.Type, personWithStaff.Id)); Assert.Equal(expectedEmailed, actualEmailed); }
public void ResolvesExpectedSupervisors(string reason, PersonWithStaff requestedBy, List <OrgGroupWithSupervisor> approvalGroups, List <OrgGroupWithSupervisor> roleGroups, Guid expectedApproverId, int expectedNotifyEmailCount) { var(actualApprover, toNotify) = LeaveService.ResolveLeaveRequestEmails(requestedBy, approvalGroups, roleGroups); if (expectedApproverId == Guid.Empty) { actualApprover.ShouldBeNull(reason); } else { actualApprover.ShouldNotBeNull(reason); actualApprover.Id.ShouldBe(expectedApproverId, reason); } toNotify.Count.ShouldBe(expectedNotifyEmailCount, reason); }
private async ValueTask <PersonWithStaff> DoNotifyWork(LeaveRequest leaveRequest, PersonWithStaff requestedBy, OrgGroupWithSupervisor orgGroup, LeaveUseage leaveUseage) { //super and requested by will be the same if the requester is a supervisor if (orgGroup == null || requestedBy.Id == orgGroup.Supervisor) { return(null); } if (orgGroup.ApproverIsSupervisor && orgGroup.SupervisorPerson != null) { await SendRequestApproval(leaveRequest, requestedBy, orgGroup.SupervisorPerson, leaveUseage); return(orgGroup.SupervisorPerson); } if (orgGroup.SupervisorPerson != null) { await NotifyOfLeaveRequest(leaveRequest, requestedBy, orgGroup.SupervisorPerson, leaveUseage); } return(null); }
public OrgGroupTests(ServicesFixture sf) { _sf = sf; _groupService = _sf.Get <OrgGroupService>(); _groupRepository = _sf.Get <OrgGroupRepository>(); _transaction = _sf.DbConnection.BeginTransaction(); var orgRootId = Guid.NewGuid(); org1Super = _sf.InsertPerson(); org1 = _sf.InsertOrgGroup(orgRootId, org1Super.Id, name: "org1", approvesLeave: true); org2Super = _sf.InsertPerson(); org2 = _sf.InsertOrgGroup(orgRootId, org2Super.Id, name: "org2", approvesLeave: true); org2a = _sf.InsertOrgGroup(org2.Id, name: "org2a"); org1aSuper = _sf.InsertPerson(); org1a = _sf.InsertOrgGroup(org1.Id, org1aSuper.Id, name: "org1a"); orgRoot = _sf.InsertOrgGroup(action: group => group.Id = orgRootId, name: "orgRoot"); org2aStaff = _sf.InsertStaff(org2a.Id); org1Staff = _sf.InsertStaff(org1.Id); org1aStaff = _sf.InsertStaff(org1a.Id); }
private async Task NotifyHr(LeaveRequest leaveRequest, PersonWithStaff requestedBy, LeaveUseage leaveUseage) { if (!ShouldNotifyHr(leaveRequest, leaveUseage)) { return; } //this is a list of substitutions avalible in the email template //these are used when notifying HR of leave //$LEAVE-SUBSTITUTIONS$ var substituions = new Dictionary <string, string> { { ":type", leaveRequest.Type.ToString() }, { ":requester", requestedBy.PreferredName + " " + requestedBy.LastName }, { ":start", leaveRequest.StartDate.ToString("MMM d yyyy") }, { ":end", leaveRequest.EndDate.ToString("MMM d yyyy") }, { ":time", $"{leaveRequest.Days} Day(s)" }, { ":left", $"{leaveUseage.Left} Day(s)" } }; await _emailService.SendTemplateEmail(substituions, $"{requestedBy.PreferredName} has requested leave", EmailTemplate.NotifyHrLeaveRequest, requestedBy, _personRepository.GetHrAdminStaff()); }
public void SetupPeople() { if (Jacob != null) { return; } var faker = PersonFaker(); Jacob = faker.Generate(); Jacob.FirstName = "Jacob"; JacobSupervisor = faker.Generate(); JacobSupervisor.FirstName = "Bob"; var jacobWife = faker.Generate(); jacobWife.SpouseId = Jacob.Id; Jacob.SpouseId = jacobWife.Id; var jacobDonor = AutoFaker.Generate <Donor>(); Jacob.DonorId = jacobDonor.Id; Assert.Empty(DbConnection.People); DbConnection.Insert(Jacob); DbConnection.Insert(jacobWife); DbConnection.Insert(JacobSupervisor); DbConnection.BulkCopy(faker.Generate(5)); DbConnection.Insert(Jacob.Staff); DbConnection.Insert(JacobSupervisor.Staff); DbConnection.Insert(jacobDonor); InsertUser("jacob", Jacob.Id, new[] { "admin" }); var jacobParentGroup = AutoFaker.Generate <OrgGroup>(); jacobParentGroup.Id = Guid.NewGuid(); jacobParentGroup.Supervisor = InsertPerson().Id; jacobParentGroup.ApproverIsSupervisor = true; DbConnection.Insert(jacobParentGroup); var jacobGroup = AutoFaker.Generate <OrgGroup>(); jacobGroup.Id = Jacob.Staff.OrgGroupId ?? Guid.Empty; jacobGroup.ParentId = jacobParentGroup.Id; jacobGroup.Supervisor = JacobSupervisor.Id; jacobGroup.ApproverIsSupervisor = true; DbConnection.Insert(jacobGroup); var jacobMissionOrg = AutoFaker.Generate <MissionOrg>(); jacobMissionOrg.Id = Jacob.Staff.MissionOrgId ?? Guid.Empty; DbConnection.Insert(jacobMissionOrg); var jacobMissionOrgYear = AutoFaker.Generate <MissionOrgYearSummary>(); jacobMissionOrgYear.MissionOrgId = jacobMissionOrg.Id; DbConnection.Insert(jacobMissionOrgYear); var jacobDonation = AutoFaker.Generate <Donation>(); jacobDonation.PersonId = Jacob.Id; jacobDonation.MissionOrgId = jacobMissionOrg.Id; DbConnection.Insert(jacobDonation); var jacobJob = InsertJob(job => { job.OrgGroup = null; job.OrgGroupId = jacobGroup.Id; }); InsertRole(role => { role.PersonId = Jacob.Id; role.JobId = jacobJob.Id; }); //endorsments var endorsement = AutoFaker.Generate <Endorsement>(); DbConnection.Insert(endorsement); var jacobEndorsement = AutoFaker.Generate <StaffEndorsement>(); jacobEndorsement.EndorsementId = endorsement.Id; jacobEndorsement.PersonId = Jacob.Id; DbConnection.Insert(jacobEndorsement); var requiredEndorsement = AutoFaker.Generate <RequiredEndorsement>(); requiredEndorsement.EndorsementId = endorsement.Id; requiredEndorsement.JobId = jacobJob.Id; DbConnection.Insert(requiredEndorsement); var education = AutoFaker.Generate <Education>(); education.PersonId = Jacob.Id; DbConnection.Insert(education); }
public IActionResult Update([FromBody] PersonWithStaff person) { _personService.Save(person); return(Json(person)); }