66 PatientStatus ,
77 ProgrammeType ,
88 SessionPresetName ,
9+ SessionStatus ,
910 SessionType ,
1011 VaccinationOutcome
1112} from '../enums.js'
@@ -19,6 +20,11 @@ import {
1920} from '../models.js'
2021import { today } from '../utils/date.js'
2122import { getResults , getPagination } from '../utils/pagination.js'
23+ import {
24+ ConjunctionType ,
25+ programmeNamesListForSentence
26+ } from '../utils/programme.js'
27+ import { queryToQueryString } from '../utils/querystring.js'
2228import { formatYearGroup , stringToArray } from '../utils/string.js'
2329
2430export const patientController = {
@@ -122,12 +128,12 @@ export const patientController = {
122128 }
123129
124130 // Filter by programme clinic status
131+ let showingClinicReady = false
125132 if ( filters . clinicStatus && filters . clinicStatus !== 'none' ) {
126- response . locals . showingClinicReady =
127- filters . clinicStatus === PatientClinicStatus . Ready
133+ showingClinicReady = filters . clinicStatus === PatientClinicStatus . Ready
134+ // Patient must have the selected clinic status for any of the selected programmes (if
135+ // there's a selected programme), or for *any* programme if not
128136 if ( programme_id ) {
129- // Patient must have the selected clinic status for any of the selected programmes (if
130- // there's a selected programme), or for *any* programme if not
131137 results = results . filter ( ( patient ) =>
132138 programme_ids . some (
133139 ( programme_id ) =>
@@ -202,8 +208,13 @@ export const patientController = {
202208
203209 // Results
204210 response . locals . patients = patients
211+ response . locals . showingClinicReady = showingClinicReady
212+ if ( showingClinicReady ) {
213+ data . clinicPatient_ids = results . map ( ( { uuid } ) => uuid )
214+ }
205215 response . locals . results = getResults ( results , request . query )
206216 response . locals . pages = getPagination ( results , request . query )
217+ response . locals . query = request . query
207218
208219 // Programme filter options
209220 response . locals . programmeItems = programmes . map ( ( programme ) => ( {
@@ -412,7 +423,7 @@ export const patientController = {
412423 response . render ( `patient/programme` )
413424 } ,
414425
415- inviteToClinic ( request , response ) {
426+ inviteOneToClinic ( request , response ) {
416427 const { patient_uuid } = request . params
417428 const { data } = request . session
418429 const { __ } = response . locals
@@ -425,21 +436,16 @@ export const patientController = {
425436 clinicProgramme_ids = stringToArray ( clinicProgramme_ids )
426437 }
427438
428- // Update the record of programmes for which the patient's been invited to clinic
429- const patient = Patient . update ( patient_uuid , { clinicProgramme_ids } , data )
430-
431439 // Send comms to parents and record in audit trail
440+ const patient = Patient . findOne ( patient_uuid , data )
432441 patient . inviteToClinic ( clinicProgramme_ids )
442+ Patient . update ( patient . uuid , patient , data )
433443
434444 // Report the success
435- const formatter = new Intl . ListFormat ( 'en' , {
436- style : 'long' ,
437- type : 'conjunction'
438- } )
439- const selectedProgrammeNames = formatter . format (
440- clinicProgramme_ids . map ( ( programme_id ) =>
441- Programme . findOne ( programme_id , data ) ?. name ?. replace ( 'Flu' , 'flu' )
442- )
445+ const selectedProgrammeNames = programmeNamesListForSentence (
446+ clinicProgramme_ids ,
447+ ConjunctionType . and ,
448+ data
443449 )
444450 request . flash (
445451 'success' ,
@@ -452,6 +458,148 @@ export const patientController = {
452458 response . redirect ( patient . uri )
453459 } ,
454460
461+ showInviteManyToClinic ( request , response ) {
462+ const { __ , __mf } = response . locals
463+ const { data } = request . session
464+ const { clinicPatient_ids } = data
465+ const { programme_id } = request . query
466+
467+ const programmes = Programme . findAll ( data )
468+ . filter ( ( programme ) => ! programme . hidden )
469+ . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
470+
471+ let programme_ids
472+ if ( programme_id ) {
473+ programme_ids = Array . isArray ( programme_id )
474+ ? programme_id
475+ : [ programme_id ]
476+ } else {
477+ programme_ids = programmes . map ( ( { id } ) => id )
478+ }
479+
480+ // e.g. 271 children can be invited to clinic for HPV, MenACWY, or Td/IPV programmes.
481+ const childrenFragment = __mf (
482+ 'patient.bulkInviteToClinic.childrenFragment' ,
483+ { count : clinicPatient_ids . length }
484+ )
485+ const programmesFragment = programme_id
486+ ? __mf ( 'patient.bulkInviteToClinic.programmesFragment' , {
487+ count : programme_ids . length ,
488+ programmeNames : programmeNamesListForSentence (
489+ programme_ids ,
490+ ConjunctionType . or ,
491+ data
492+ )
493+ } )
494+ : __ ( 'patient.bulkInviteToClinic.anyProgrammesFragment' )
495+ response . locals . cohortSummary = __ (
496+ 'patient.bulkInviteToClinic.cohortSummary' ,
497+ { children : childrenFragment , programmes : programmesFragment }
498+ )
499+
500+ // Create the programme checkboxes and their patient and clinic counts
501+ const checkboxItems = [ ]
502+ const scheduledSessions = Session . findAll ( data )
503+ . filter ( ( { type } ) => type === SessionType . Clinic )
504+ . filter ( ( { status } ) => status === SessionStatus . Planned )
505+ const invitableProgrammes = programmes . filter ( ( programme ) =>
506+ programme_ids . includes ( programme . id )
507+ )
508+ for ( const programme of invitableProgrammes ) {
509+ const clinicReadyChildrenCount = clinicPatient_ids
510+ . map ( ( id ) => Patient . findOne ( id , data ) )
511+ . filter (
512+ ( patient ) =>
513+ patient . programmes [ programme . id ] . clinicStatus ===
514+ PatientClinicStatus . Ready
515+ ) . length
516+ if ( clinicReadyChildrenCount > 0 ) {
517+ const scheduledClinicCount = scheduledSessions . filter ( ( session ) =>
518+ session . programme_ids . includes ( programme . id )
519+ ) . length
520+
521+ const childrenHint = __mf (
522+ 'patient.bulkInviteToClinic.programme.hint.children' ,
523+ {
524+ count : clinicReadyChildrenCount ,
525+ programmeName : programme . name
526+ }
527+ )
528+ const clinicsHint = __mf (
529+ 'patient.bulkInviteToClinic.programme.hint.clinics' ,
530+ {
531+ count : scheduledClinicCount ,
532+ programmeName : programme . name
533+ }
534+ )
535+ checkboxItems . push ( {
536+ text : programme . name ,
537+ value : programme . id ,
538+ hint : {
539+ html : __ ( 'patient.bulkInviteToClinic.programme.hint.combined' , {
540+ childrenHint,
541+ clinicsHint
542+ } )
543+ }
544+ } )
545+ }
546+ }
547+
548+ response . locals . checkboxItems = checkboxItems
549+
550+ response . render ( 'patient/bulk-invite-to-clinic' )
551+ } ,
552+
553+ inviteManyToClinic ( request , response ) {
554+ let { clinicProgramme_ids } = request . body
555+ const { __mf } = response . locals
556+ const { data } = request . session
557+ const { clinicPatient_ids } = data
558+
559+ // Tidy up any _unchecked values
560+ if ( typeof clinicProgramme_ids === 'string' ) {
561+ clinicProgramme_ids = [ clinicProgramme_ids ]
562+ } else {
563+ clinicProgramme_ids = stringToArray ( clinicProgramme_ids )
564+ }
565+
566+ // Invite each of the children to clinic for the subset of the selected programmes
567+ // that make sense for that child
568+ let invitedChildrenCount = 0
569+ for ( const patient of clinicPatient_ids . map ( ( id ) =>
570+ Patient . findOne ( id , data )
571+ ) ) {
572+ // Work out which of the selected programmes this patient was clinic-ready for
573+ const { clinicReadyProgramme_ids } = patient
574+ const invitedProgramme_ids = [
575+ ...new Set ( clinicReadyProgramme_ids ) . intersection (
576+ new Set ( clinicProgramme_ids )
577+ )
578+ ]
579+
580+ if ( invitedProgramme_ids . length ) {
581+ // Send comms to parents and record in audit trail
582+ patient . inviteToClinic ( invitedProgramme_ids )
583+ Patient . update ( patient . uuid , patient , data )
584+
585+ invitedChildrenCount ++
586+ }
587+ }
588+
589+ request . flash (
590+ 'success' ,
591+ __mf ( 'patient.bulkInviteToClinic.success' , {
592+ count : invitedChildrenCount
593+ } )
594+ )
595+
596+ // Reset the cohort
597+ delete data . clinicPatient_ids
598+
599+ // Get back to the filter page as we left it
600+ response . redirect ( `/patients${ queryToQueryString ( request . query ) } ` )
601+ } ,
602+
455603 archive ( request , response ) {
456604 const { account } = request . app . locals
457605 const { patient_uuid } = request . params
0 commit comments