Skip to content

Commit c6b53c5

Browse files
atGit2021CarsonF
andauthored
Update Project Workflow for Multiplication Projects (#3184)
Co-authored-by: Carson Full <[email protected]>
1 parent 6497f29 commit c6b53c5

File tree

5 files changed

+115
-46
lines changed

5 files changed

+115
-46
lines changed

src/components/project/handlers/send-step-change-notification-on-change-request-approved.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { EmailService } from '@seedcompany/nestjs-email';
22
import { node, relation } from 'cypher-query-builder';
3-
import { ID } from '../../../common';
43
import {
54
ConfigService,
65
DatabaseService,
@@ -12,7 +11,7 @@ import {
1211
import { ACTIVE, INACTIVE } from '../../../core/database/query';
1312
import { ProjectStepChanged } from '../../../core/email/templates';
1413
import { ProjectChangeRequestApprovedEvent } from '../../project-change-request/events';
15-
import { ProjectStep } from '../dto';
14+
import { Project, ProjectStep } from '../dto';
1615
import { ProjectRules } from '../project.rules';
1716

1817
type SubscribedEvent = ProjectChangeRequestApprovedEvent;
@@ -56,11 +55,11 @@ export class SendStepChangeNotificationsOnChangeRequestApproved
5655
.with('node, currentStep, previousStep')
5756
.orderBy('previousStep.createdAt', 'DESC')
5857
.return<{
59-
projectId: ID;
58+
project: Pick<Project, 'id' | 'type'>;
6059
currentStep: ProjectStep;
6160
previousStep: ProjectStep;
6261
}>(
63-
'node.id as projectId, currentStep.value as currentStep, collect(previousStep.value)[0] as previousStep',
62+
'node { .id, .type } as project, currentStep.value as currentStep, collect(previousStep.value)[0] as previousStep',
6463
)
6564
.first();
6665

@@ -73,15 +72,16 @@ export class SendStepChangeNotificationsOnChangeRequestApproved
7372
}
7473

7574
const recipients = await this.projectRules.getNotifications(
76-
result.projectId,
75+
result.project.id,
76+
result.project.type,
7777
result.currentStep,
7878
event.session.userId,
7979
result.previousStep,
8080
);
8181

8282
this.logger.info('Notifying', {
8383
emails: recipients.map((r) => r.recipient.email.value),
84-
projectId: result.projectId,
84+
projectId: result.project.id,
8585
step: result.currentStep,
8686
previousStep: result.previousStep,
8787
});

src/components/project/handlers/step-changed-notification.handler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class ProjectStepChangedNotificationHandler
3232

3333
const recipients = await this.projectRules.getNotifications(
3434
event.updated.id,
35+
event.updated.type,
3536
event.updated.step,
3637
event.session.userId,
3738
event.previous.step,

src/components/project/project-step.resolver.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
2+
import { Loader, LoaderOf } from '@seedcompany/data-loader';
23
import { stripIndent } from 'common-tags';
3-
import { AnonSession, ID, Session } from '../../common';
4+
import { AnonSession, ID, Session, viewOfChangeset } from '~/common';
45
import { ProjectStepTransition, SecuredProjectStep } from './dto';
6+
import { ProjectLoader } from './project.loader';
57
import { ProjectRules } from './project.rules';
68

79
@Resolver(SecuredProjectStep)
@@ -13,14 +15,20 @@ export class ProjectStepResolver {
1315
})
1416
async transitions(
1517
@Parent() step: SecuredProjectStep & { parentId: ID; changeset?: ID },
18+
@Loader(ProjectLoader) projects: LoaderOf<ProjectLoader>,
1619
@AnonSession() session: Session,
1720
): Promise<ProjectStepTransition[]> {
1821
if (!step.canRead || !step.canEdit || !step.value) {
1922
return [];
2023
}
24+
const project = await projects.load({
25+
id: step.parentId,
26+
view: viewOfChangeset(step.changeset),
27+
});
2128
return await this.projectRules.getAvailableTransitions(
2229
step.parentId,
2330
session,
31+
project.type,
2432
undefined,
2533
step.changeset,
2634
);

src/components/project/project.rules.ts

Lines changed: 98 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ import {
1111
ServerException,
1212
Session,
1313
UnauthorizedException,
14+
UnsecuredDto,
1415
} from '../../common';
1516
import { ConfigService, DatabaseService, ILogger, Logger } from '../../core';
1617
import { ACTIVE, INACTIVE } from '../../core/database/query';
1718
import { AuthenticationService } from '../authentication';
1819
import { Role, withoutScope } from '../authorization';
1920
import { EngagementService, EngagementStatus } from '../engagement';
21+
import { ProjectType } from '../project';
2022
import { User, UserService } from '../user';
2123
import {
2224
Project,
@@ -78,10 +80,13 @@ export class ProjectRules {
7880
private async getStepRule(
7981
step: ProjectStep,
8082
id: ID,
83+
projectType: ProjectType,
8184
changeset?: ID,
8285
): Promise<StepRule> {
8386
const mostRecentPreviousStep = (steps: ProjectStep[]) =>
8487
this.getMostRecentPreviousStep(id, steps, changeset);
88+
const isMultiplication =
89+
projectType === ProjectType.MultiplicationTranslation;
8590

8691
switch (step) {
8792
case ProjectStep.EarlyConversations:
@@ -93,11 +98,26 @@ export class ProjectRules {
9398
Role.FieldOperationsDirector,
9499
],
95100
transitions: [
96-
{
97-
to: ProjectStep.PendingConceptApproval,
98-
type: TransitionType.Approve,
99-
label: 'Submit for Concept Approval',
100-
},
101+
...(isMultiplication
102+
? [
103+
{
104+
to: ProjectStep.PendingRegionalDirectorApproval,
105+
type: TransitionType.Approve,
106+
label: 'Submit for Regional Director Approval',
107+
},
108+
{
109+
to: ProjectStep.PendingFinanceConfirmation,
110+
type: TransitionType.Approve,
111+
label: 'Submit for Finance Confirmation',
112+
},
113+
]
114+
: [
115+
{
116+
to: ProjectStep.PendingConceptApproval,
117+
type: TransitionType.Approve,
118+
label: 'Submit for Concept Approval',
119+
},
120+
]),
101121
{
102122
to: ProjectStep.DidNotDevelop,
103123
type: TransitionType.Reject,
@@ -281,21 +301,41 @@ export class ProjectRules {
281301
Role.FieldOperationsDirector,
282302
],
283303
transitions: [
284-
{
285-
to: ProjectStep.PendingFinanceConfirmation,
286-
type: TransitionType.Approve,
287-
label: 'Approve Project',
288-
},
289-
{
290-
to: ProjectStep.PendingZoneDirectorApproval,
291-
type: TransitionType.Approve,
292-
label: 'Approve for Zonal Director Review',
293-
},
294-
{
295-
to: ProjectStep.FinalizingProposal,
296-
type: TransitionType.Reject,
297-
label: 'Send Back for Corrections',
298-
},
304+
...(isMultiplication
305+
? [
306+
{
307+
to: ProjectStep.EarlyConversations,
308+
type: TransitionType.Reject,
309+
label: 'Send Back for Corrections',
310+
},
311+
{
312+
to: ProjectStep.PendingFinanceConfirmation,
313+
type: TransitionType.Approve,
314+
label: 'Submit for Finance Confirmation',
315+
},
316+
{
317+
to: ProjectStep.DidNotDevelop,
318+
type: TransitionType.Reject,
319+
label: 'End Development',
320+
},
321+
]
322+
: [
323+
{
324+
to: ProjectStep.PendingFinanceConfirmation,
325+
type: TransitionType.Approve,
326+
label: 'Approve Project',
327+
},
328+
{
329+
to: ProjectStep.PendingZoneDirectorApproval,
330+
type: TransitionType.Approve,
331+
label: 'Approve for Zonal Director Review',
332+
},
333+
{
334+
to: ProjectStep.FinalizingProposal,
335+
type: TransitionType.Reject,
336+
label: 'Send Back for Corrections',
337+
},
338+
]),
299339
{
300340
to: ProjectStep.Rejected,
301341
type: TransitionType.Reject,
@@ -330,6 +370,36 @@ export class ProjectRules {
330370
return {
331371
approvers: [Role.Administrator, Role.Controller],
332372
transitions: [
373+
...(isMultiplication
374+
? [
375+
{
376+
to: ProjectStep.PendingRegionalDirectorApproval,
377+
type: TransitionType.Reject,
378+
label: 'Send Back for Corrections',
379+
},
380+
{
381+
to: ProjectStep.DidNotDevelop,
382+
type: TransitionType.Reject,
383+
label: 'End Development',
384+
},
385+
]
386+
: [
387+
{
388+
to: ProjectStep.OnHoldFinanceConfirmation,
389+
type: TransitionType.Neutral,
390+
label: 'Hold Project for Confirmation',
391+
},
392+
{
393+
to: ProjectStep.FinalizingProposal,
394+
type: TransitionType.Reject,
395+
label: 'Send Back for Corrections',
396+
},
397+
{
398+
to: ProjectStep.Rejected,
399+
type: TransitionType.Reject,
400+
label: 'Reject',
401+
},
402+
]),
333403
{
334404
to: ProjectStep.Active,
335405
type: TransitionType.Approve,
@@ -340,21 +410,6 @@ export class ProjectRules {
340410
341411
],
342412
},
343-
{
344-
to: ProjectStep.OnHoldFinanceConfirmation,
345-
type: TransitionType.Neutral,
346-
label: 'Hold Project for Confirmation',
347-
},
348-
{
349-
to: ProjectStep.FinalizingProposal,
350-
type: TransitionType.Reject,
351-
label: 'Send Back for Corrections',
352-
},
353-
{
354-
to: ProjectStep.Rejected,
355-
type: TransitionType.Reject,
356-
label: 'Reject',
357-
},
358413
],
359414
getNotifiers: async () => [
360415
...(await this.getProjectTeamUserIds(id)),
@@ -823,6 +878,7 @@ export class ProjectRules {
823878
async getAvailableTransitions(
824879
projectId: ID,
825880
session: Session,
881+
projectType: ProjectType,
826882
currentUserRoles?: Role[],
827883
changeset?: ID,
828884
): Promise<ProjectStepTransition[]> {
@@ -836,6 +892,7 @@ export class ProjectRules {
836892
const { approvers, transitions } = await this.getStepRule(
837893
currentStep,
838894
projectId,
895+
projectType,
839896
changeset,
840897
);
841898

@@ -854,7 +911,7 @@ export class ProjectRules {
854911
}
855912

856913
async verifyStepChange(
857-
projectId: ID,
914+
project: UnsecuredDto<Project>,
858915
session: Session,
859916
nextStep: ProjectStep,
860917
changeset?: ID,
@@ -867,8 +924,9 @@ export class ProjectRules {
867924
}
868925

869926
const transitions = await this.getAvailableTransitions(
870-
projectId,
927+
project.id,
871928
session,
929+
project.type,
872930
currentUserRoles,
873931
changeset,
874932
);
@@ -924,6 +982,7 @@ export class ProjectRules {
924982

925983
async getNotifications(
926984
projectId: ID,
985+
projectType: ProjectType,
927986
step: ProjectStep,
928987
changedById: ID,
929988
previousStep: ProjectStep,
@@ -932,11 +991,12 @@ export class ProjectRules {
932991
const { getNotifiers: arrivalNotifiers } = await this.getStepRule(
933992
step,
934993
projectId,
994+
projectType,
935995
changeset,
936996
);
937997

938998
const transitionNotifiers = (
939-
await this.getStepRule(previousStep, projectId)
999+
await this.getStepRule(previousStep, projectId, projectType)
9401000
).transitions.find((t) => t.to === step)?.notifiers;
9411001

9421002
const resolve = async (notifiers?: Notifiers) =>

src/components/project/project.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ export class ProjectService {
267267

268268
if (changes.step && stepValidation) {
269269
await this.projectRules.verifyStepChange(
270-
input.id,
270+
currentProject,
271271
session,
272272
changes.step,
273273
changeset,

0 commit comments

Comments
 (0)