diff --git a/backend/emails/emails.js b/backend/emails/emails.js index 0264de0..77acdac 100644 --- a/backend/emails/emails.js +++ b/backend/emails/emails.js @@ -174,7 +174,7 @@ const sendEmailUPRPurchasedToReporter = async (upr) => { `Your UW Finance Purchase Request has been purchased! When the item is ready to be picked up, we will let you know.` ) + (await getUPRTicketInfoHTML(upr)) + - +getTicketLinkHTML(upr.path) + getTicketLinkHTML(upr.path) const To = await getEmailToSection(upr.reporter_id, [ EMAIL_RECIPIENTS.reporter, ]) @@ -205,6 +205,25 @@ const sendEmailUPRPurchasedToCoordinator = async (upr) => { }) } +const sendEmailUPRReadyForPickupToCoordinator = async (upr) => { + const Subject = `[Ready for pickup] ${upr.codename}` + const HTMLPart = + getMainMessageHTML( + 'Your UW Finance Request is ready to be picked up! Please view the ticket below for pickup instructions and confirm when you have picked it up.' + ) + + (await getUPRTicketInfoHTML(upr)) + + getTicketLinkHTML(upr.path) + const To = await getEmailToSection(upr.reporter_id, [ + EMAIL_RECIPIENTS.reporter, + ]) + + await sendEmail({ + Subject, + HTMLPart, + To, + }) +} + const sendEmailPPRApprovedToReporter = async (ppr) => { const Subject = `[Ready to Buy] ${ppr.codename}` const HTMLPart = @@ -287,7 +306,7 @@ const sendEmailSFReimbursementRequestToCoordinator = async (sf) => { const Subject = `[Action Needed] Submit Reimbursement Request ${sf.codename}` const HTMLPart = getMainMessageHTML( - `Claim has been submitted for ${sf.codename}! Please review it and submit a reimbursement request. Visit the ticket link below to confirm you have submitted the reimbursement request.` + `Please review the claim and submit a reimbursement request for ${sf.codename}. Once submitted, please visit the ticket link below to confirm that you have submitted it.` ) + (await getSFTicketInfoHTML(sf)) + getTicketLinkHTML(sf.path) @@ -305,7 +324,7 @@ const sendEmailSFConfirmReimbursementSubmitToCoordinator = async (sf) => { const Subject = `[Action Needed] Confirm Reimbursement Received ${sf.codename}` const HTMLPart = getMainMessageHTML( - `Please visit the ticket link below to confirm you have received the reimbursement for ${sf.codename}.` + `Once the sponsorship fund for ${sf.codename} has reimbursed us, please visit the ticket link below to confirm it.` ) + (await getSFTicketInfoHTML(sf)) + getTicketLinkHTML(sf.path) @@ -322,7 +341,7 @@ const sendEmailSFConfirmReimbursementSubmitToCoordinator = async (sf) => { const sendEmailSFReimbursementReceivedToTeam = async (sf) => { const Subject = `[Reimbursed] ${sf.codename}` const HTMLPart = - getMainMessageHTML(`${sf.codename} has been reimbursed.`) + + getMainMessageHTML(`${sf.codename} has been reimbursed!`) + (await getSFTicketInfoHTML(sf)) + getTicketLinkHTML(sf.path) const To = await getEmailToSection(sf.reporter_id, [ @@ -662,6 +681,7 @@ module.exports = { sendEmailUPRApprovedToCoordinator, sendEmailUPRPurchasedToReporter, sendEmailUPRPurchasedToCoordinator, + sendEmailUPRReadyForPickupToCoordinator, sendEmailPPRApprovedToReporter, sendEmailPPRCreatedToApprovers, sendEmailPPRPurchasedAndReceiptsSubmittedToCoordinator, diff --git a/backend/models/constants.js b/backend/models/constants.js index 9af68f8..6230073 100644 --- a/backend/models/constants.js +++ b/backend/models/constants.js @@ -20,10 +20,10 @@ const UPR_STATUS = [ 'SEEKING_APPROVAL', 'SENT_TO_COORDINATOR', 'ORDERED', + 'READY_FOR_PICKUP', 'PICKED_UP', ] - -const UPR_STATUS_FUNDING_SPENT = ['ORDERED', 'PICKED_UP'] +const UPR_STATUS_FUNDING_SPENT = ['ORDERED', 'READY_FOR_PICKUP', 'PICKED_UP'] const APPROVAL_LEVELS = Object.freeze({ director_approval: 'director_approval', diff --git a/backend/service/personalpurchases.service.js b/backend/service/personalpurchases.service.js index ce22ae0..f4c1500 100644 --- a/backend/service/personalpurchases.service.js +++ b/backend/service/personalpurchases.service.js @@ -33,15 +33,17 @@ const createPersonalPurchase = async (body) => { } const updatePersonalPurchase = async (id, body) => { - // READY_TO_BUY -> PURCHASED_AND_RECEIPTS_SUBMITTED const newPurchaseTicket = PersonalPurchase.findByIdAndUpdate(id, body, { new: true, }) const annotatedPPR = await getPersonalPurchase(id) + + // READY_TO_BUY -> PURCHASED_AND_RECEIPTS_SUBMITTED if (body?.status === 'PURCHASED_AND_RECEIPTS_SUBMITTED') { await sendEmailPPRPurchasedAndReceiptsSubmittedToCoordinator( annotatedPPR ) + // PURCHASED_AND_RECEIPTS_SUBMITTED -> REPORTER_PAID } else if (body?.status === 'REPORTER_PAID') { await sendEmailPPRReimbursedToReporter(annotatedPPR) } diff --git a/backend/service/sponsorshipfunds.service.js b/backend/service/sponsorshipfunds.service.js index 9db03ca..f38ef9c 100644 --- a/backend/service/sponsorshipfunds.service.js +++ b/backend/service/sponsorshipfunds.service.js @@ -67,17 +67,19 @@ const updateSponsorshipFund = async (id, body) => { const status = annotatedSponsorshipFund.status if (status === 'CLAIM_SUBMITTED') { - sendEmailSFReimbursementRequestToCoordinator(annotatedSponsorshipFund) + await sendEmailSFReimbursementRequestToCoordinator( + annotatedSponsorshipFund + ) } if (status === 'SUBMITTED_TO_SF') { - sendEmailSFConfirmReimbursementSubmitToCoordinator( + await sendEmailSFConfirmReimbursementSubmitToCoordinator( annotatedSponsorshipFund ) } if (status === 'REIMBURSED') { - sendEmailSFReimbursementReceivedToTeam(annotatedSponsorshipFund) + await sendEmailSFReimbursementReceivedToTeam(annotatedSponsorshipFund) } return newSponsorshipFund diff --git a/backend/service/uwfinancepurchases.service.js b/backend/service/uwfinancepurchases.service.js index 66e1969..cbc5097 100644 --- a/backend/service/uwfinancepurchases.service.js +++ b/backend/service/uwfinancepurchases.service.js @@ -9,6 +9,7 @@ const { sendEmailUPRApprovedToCoordinator, sendEmailUPRPurchasedToCoordinator, sendEmailUPRPurchasedToReporter, + sendEmailUPRReadyForPickupToCoordinator, } = require('../emails/emails') const getAllUWFinancePurchases = () => { @@ -33,8 +34,6 @@ const createNewUWFinancePurchase = async (body) => { } const updateUWFinancePurchase = async (id, body) => { - const existingPurchaseTicket = await getUWFinancePurchase(id) - // SENT_TO_COORDINATOR -> ORDERED const newPurchaseTicket = await UWFinancePurchase.findByIdAndUpdate( id, body, @@ -42,10 +41,8 @@ const updateUWFinancePurchase = async (id, body) => { new: true, } ) - if ( - existingPurchaseTicket.status === 'SENT_TO_COORDINATOR' && - body.status === 'ORDERED' - ) { + // SENT_TO_COORDINATOR -> ORDERED + if (body.status === 'ORDERED') { const annotatedUPR = await getUWFinancePurchase(id) const emails = [ sendEmailUPRPurchasedToCoordinator(annotatedUPR), @@ -53,6 +50,11 @@ const updateUWFinancePurchase = async (id, body) => { ] await Promise.all(emails) } + // ORDERED -> READY_FOR_PICKUP + if (body.status === 'READY_FOR_PICKUP') { + const annotatedUPR = await getUWFinancePurchase(id) + await sendEmailUPRReadyForPickupToCoordinator(annotatedUPR) + } return newPurchaseTicket } diff --git a/frontend/src/components/ConfirmationModal.js b/frontend/src/components/ConfirmationModal.js index 7bd7720..7ab4b61 100644 --- a/frontend/src/components/ConfirmationModal.js +++ b/frontend/src/components/ConfirmationModal.js @@ -9,19 +9,14 @@ import { Button, } from '@chakra-ui/react' -const ConfirmationModal = ({ onConfirm, isOpen, onClose }) => { +const ConfirmationModal = ({ title, body, onConfirm, isOpen, onClose }) => { return ( - Submission (Placeholder) + {title} - -
- Are you sure you want to submit this, you cant undo bla - bla bla (PLACEHOLDER) -
-
+ {body} )} {/* can remove getPreserveParamsHref if it does not make sense to preserve params */} diff --git a/frontend/src/components/TicketContent/UPRAdminContentTable.js b/frontend/src/components/TicketContent/UPRAdminContentTable.js index 7068d5f..92dad71 100644 --- a/frontend/src/components/TicketContent/UPRAdminContentTable.js +++ b/frontend/src/components/TicketContent/UPRAdminContentTable.js @@ -1,5 +1,6 @@ import { Button, Center, Heading, Table, Tbody, VStack } from '@chakra-ui/react' -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' +import { useLocation } from 'react-router-dom' import { useSetRecoilState } from 'recoil' import TicketContentTableRow from './TicketContentTableRow' import { allTicketsState } from '../../state/atoms' @@ -9,6 +10,7 @@ import { getAllTickets } from '../../utils/globalSetters' import { useGetCurrentTicket } from '../../hooks/hooks' const UPRAdminContentTable = () => { + const location = useLocation() const currentTicket = useGetCurrentTicket() const [reqNum, setReqNum] = useState(currentTicket.requisition_number) const [poNum, setPoNum] = useState(currentTicket.po_number) @@ -23,6 +25,15 @@ const UPRAdminContentTable = () => { setChanged(true) } + useEffect(() => { + setReqNum(currentTicket.requisition_number ?? '') + setPoNum(currentTicket.po_number ?? '') + }, [ + location.pathname, + currentTicket.requisition_number, + currentTicket.po_number, + ]) + const saveFields = async () => { const payload = { requisition_number: reqNum, @@ -50,6 +61,18 @@ const UPRAdminContentTable = () => { setChanged(false) } + const transitionToReadyForPickup = async () => { + const payload = { + status: 'READY_FOR_PICKUP', + } + await axiosPreset.patch( + `${TICKET_ENDPOINTS.UPR}/${currentTicket._id}`, + payload + ) + await getAllTickets(setAllTickets) + setChanged(false) + } + const transitionToPickedUp = async () => { const payload = { status: 'PICKED_UP', @@ -98,6 +121,16 @@ const UPRAdminContentTable = () => { )} {currentTicket.status === 'ORDERED' && ( + + )} + {currentTicket.status === 'READY_FOR_PICKUP' && (