Skip to content

Commit ceeb798

Browse files
authored
Merge pull request #6823 from espoon-voltti/create-child-documents
Lisätään kuntalaisen lomakkeen massalähetys
2 parents c25b3c3 + 78d6acb commit ceeb798

File tree

17 files changed

+767
-112
lines changed

17 files changed

+767
-112
lines changed

frontend/src/e2e-test/pages/employee/units/unit-groups-page.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
import { waitUntilDefined, waitUntilEqual, waitUntilTrue } from '../../../utils'
66
import {
7+
Combobox,
78
DatePicker,
89
DatePickerDeprecated,
910
Element,
1011
ElementCollection,
1112
Modal,
13+
MultiSelect,
1214
Page,
1315
TextInput
1416
} from '../../../utils/page'
@@ -21,6 +23,7 @@ export class UnitGroupsPage {
2123
terminatedPlacementsSection: TerminatedPlacementsSection
2224
missingPlacementsSection: MissingPlacementsSection
2325
childCapacityFactorColumnData: ElementCollection
26+
2427
constructor(private readonly page: Page) {
2528
this.childCapacityFactorColumnHeading = page.findByDataQa(
2629
`child-capacity-factor-heading`
@@ -100,6 +103,7 @@ export class UnitGroupsPage {
100103

101104
export class TerminatedPlacementsSection extends Element {
102105
#terminatedPlacementRows: ElementCollection
106+
103107
constructor(page: Page, self: Element) {
104108
super(self)
105109
this.#terminatedPlacementRows = page.findAll(
@@ -219,6 +223,7 @@ export class GroupCollapsible extends Element {
219223

220224
#monthCalendarButton = this.find('[data-qa="open-month-calendar-button"]')
221225
#groupDailyNoteButton = this.find('[data-qa="btn-create-group-note"]')
226+
createChildDocumentsButton = this.findByDataQa('btn-create-child-documents')
222227

223228
#childRows = this.find('[data-qa="table-of-group-placements"]').findAll(
224229
'[data-qa^="group-placement-row-"]'
@@ -259,6 +264,11 @@ export class GroupCollapsible extends Element {
259264
return new GroupDailyNoteModal(this.find('[data-qa="modal"]'))
260265
}
261266

267+
async openCreateChildDocumentsModal() {
268+
await this.createChildDocumentsButton.click()
269+
return new CreateChildDocumentsModal(this.findByDataQa('modal'))
270+
}
271+
262272
#updateButton = this.find('[data-qa="btn-update-group"]')
263273

264274
async edit(fields: { name: string; startDate: string; endDate: string }) {
@@ -296,9 +306,25 @@ export class GroupDailyNoteModal extends Modal {
296306
}
297307
}
298308

309+
export class CreateChildDocumentsModal extends Modal {
310+
templateSelect: Combobox
311+
childrenSelect: MultiSelect
312+
313+
constructor(self: Element) {
314+
super(self)
315+
this.templateSelect = new Combobox(
316+
self.findByDataQa('create-child-documents-modal-select-template')
317+
)
318+
this.childrenSelect = new MultiSelect(
319+
self.findByDataQa('create-child-documents-modal-select-children')
320+
)
321+
}
322+
}
323+
299324
export class GroupCollapsibleChildRow extends Element {
300325
#dailyNoteIcon: Element
301326
#dailyNoteTooltip: Element
327+
302328
constructor(self: Element, childId: string) {
303329
super(self)
304330
this.#dailyNoteIcon = this.find(

frontend/src/e2e-test/specs/5_employee/child-documents.spec.ts

Lines changed: 271 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ import {
1919
resetServiceState,
2020
runJobs
2121
} from '../../generated/api-clients'
22-
import { DevEmployee } from '../../generated/api-types'
22+
import {
23+
DevDaycare,
24+
DevDaycareGroup,
25+
DevDocumentTemplate,
26+
DevEmployee,
27+
DevPerson
28+
} from '../../generated/api-types'
2329
import ChildInformationPage from '../../pages/employee/child-information'
2430
import { ChildDocumentPage } from '../../pages/employee/documents/child-document'
2531
import {
@@ -28,39 +34,39 @@ import {
2834
} from '../../pages/employee/documents/document-templates'
2935
import EmployeeNav from '../../pages/employee/employee-nav'
3036
import { ChildDocumentsReport } from '../../pages/employee/reports'
37+
import { UnitPage } from '../../pages/employee/units/unit'
3138
import { waitUntilEqual } from '../../utils'
3239
import { Page } from '../../utils/page'
3340
import { employeeLogin } from '../../utils/user'
3441

35-
let admin: DevEmployee
36-
let unitSupervisor: DevEmployee
37-
let page: Page
38-
3942
const now = HelsinkiDateTime.of(2023, 2, 1, 12, 10, 0)
4043

41-
beforeEach(async () => {
42-
await resetServiceState()
43-
44-
await Fixture.careArea(testCareArea).save()
45-
await Fixture.daycare(testDaycare).save()
46-
await Fixture.person(testAdult).saveAdult()
47-
await Fixture.person(testChild2).saveChild()
48-
await Fixture.guardian(testChild2, testAdult).save()
49-
admin = await Fixture.employee().admin().save()
50-
unitSupervisor = await Fixture.employee()
51-
.unitSupervisor(testDaycare.id)
52-
.save()
53-
54-
await Fixture.placement({
55-
childId: testChild2.id,
56-
unitId: testDaycare.id,
57-
startDate: now.toLocalDate().subYears(1),
58-
endDate: now.toLocalDate().addYears(1),
59-
type: 'PRESCHOOL'
60-
}).save()
61-
})
44+
beforeEach(async () => await resetServiceState())
6245

6346
describe('Employee - Child documents', () => {
47+
let admin: DevEmployee
48+
let unitSupervisor: DevEmployee
49+
let page: Page
50+
51+
beforeEach(async () => {
52+
await Fixture.careArea(testCareArea).save()
53+
await Fixture.daycare(testDaycare).save()
54+
await Fixture.person(testAdult).saveAdult()
55+
await Fixture.person(testChild2).saveChild()
56+
await Fixture.guardian(testChild2, testAdult).save()
57+
admin = await Fixture.employee().admin().save()
58+
unitSupervisor = await Fixture.employee()
59+
.unitSupervisor(testDaycare.id)
60+
.save()
61+
62+
await Fixture.placement({
63+
childId: testChild2.id,
64+
unitId: testDaycare.id,
65+
startDate: now.toLocalDate().subYears(1),
66+
endDate: now.toLocalDate().addYears(1),
67+
type: 'PRESCHOOL'
68+
}).save()
69+
})
6470
test('Full basic workflow for hojks', async () => {
6571
// Admin creates a template
6672

@@ -722,3 +728,242 @@ describe('Employee - Child documents', () => {
722728
)
723729
})
724730
})
731+
732+
describe('Employee - Child documents - unit groups page', () => {
733+
let template: DevDocumentTemplate
734+
let unit1: DevDaycare
735+
let group1: DevDaycareGroup
736+
let group2: DevDaycareGroup
737+
let child0WithoutGroup: DevPerson
738+
let child1InGroup1: DevPerson
739+
let child2InGroup1: DevPerson
740+
let child3InGroup1: DevPerson
741+
let child4InGroup2: DevPerson
742+
let child5InGroup2: DevPerson
743+
744+
const savePlacementAndGrouping = async (
745+
unit: DevDaycare,
746+
child: DevPerson,
747+
group?: DevDaycareGroup
748+
) => {
749+
const placement = await Fixture.placement({
750+
unitId: unit.id,
751+
childId: child.id,
752+
startDate: now.toLocalDate().subYears(1),
753+
endDate: now.toLocalDate().addYears(1),
754+
type: 'PRESCHOOL'
755+
}).save()
756+
if (group !== undefined) {
757+
await Fixture.groupPlacement({
758+
daycarePlacementId: placement.id,
759+
daycareGroupId: group.id,
760+
startDate: placement.startDate,
761+
endDate: placement.endDate
762+
}).save()
763+
}
764+
return placement
765+
}
766+
767+
beforeEach(async () => {
768+
await Fixture.serviceNeedOption({
769+
validPlacementType: 'PRESCHOOL',
770+
defaultOption: true
771+
}).save()
772+
const area = await Fixture.careArea().save()
773+
unit1 = await Fixture.daycare({
774+
areaId: area.id,
775+
enabledPilotFeatures: ['VASU_AND_PEDADOC']
776+
}).save()
777+
group1 = await Fixture.daycareGroup({
778+
daycareId: unit1.id
779+
}).save()
780+
group2 = await Fixture.daycareGroup({
781+
daycareId: unit1.id
782+
}).save()
783+
child0WithoutGroup = await Fixture.person({
784+
ssn: null,
785+
lastName: '4',
786+
firstName: 'child'
787+
}).saveChild()
788+
child1InGroup1 = await Fixture.person({
789+
ssn: null,
790+
lastName: '1',
791+
firstName: 'child'
792+
}).saveChild()
793+
child2InGroup1 = await Fixture.person({
794+
ssn: null,
795+
lastName: '2',
796+
firstName: 'child'
797+
}).saveChild()
798+
child3InGroup1 = await Fixture.person({
799+
ssn: null,
800+
lastName: '3',
801+
firstName: 'child'
802+
}).saveChild()
803+
child4InGroup2 = await Fixture.person({
804+
ssn: null,
805+
lastName: '4',
806+
firstName: 'child'
807+
}).saveChild()
808+
child5InGroup2 = await Fixture.person({
809+
ssn: null,
810+
lastName: '5',
811+
firstName: 'child'
812+
}).saveChild()
813+
const adult1 = await Fixture.person({
814+
ssn: null,
815+
816+
}).saveAdult()
817+
await Fixture.guardian(child0WithoutGroup, adult1).save()
818+
await Fixture.guardian(child1InGroup1, adult1).save()
819+
await Fixture.guardian(child2InGroup1, adult1).save()
820+
await Fixture.guardian(child3InGroup1, adult1).save()
821+
await Fixture.guardian(child4InGroup2, adult1).save()
822+
await Fixture.guardian(child5InGroup2, adult1).save()
823+
await savePlacementAndGrouping(unit1, child0WithoutGroup)
824+
await savePlacementAndGrouping(unit1, child1InGroup1, group1)
825+
await savePlacementAndGrouping(unit1, child2InGroup1, group1)
826+
const child3Placement = await savePlacementAndGrouping(
827+
unit1,
828+
child3InGroup1
829+
)
830+
await Fixture.groupPlacement({
831+
daycarePlacementId: child3Placement.id,
832+
daycareGroupId: group1.id,
833+
startDate: child3Placement.startDate,
834+
endDate: now.toLocalDate()
835+
}).save()
836+
await Fixture.groupPlacement({
837+
daycarePlacementId: child3Placement.id,
838+
daycareGroupId: group1.id,
839+
startDate: now.toLocalDate().addDays(2),
840+
endDate: child3Placement.endDate
841+
}).save()
842+
await savePlacementAndGrouping(unit1, child4InGroup2, group2)
843+
await savePlacementAndGrouping(unit1, child5InGroup2, group2)
844+
template = await Fixture.documentTemplate({
845+
type: 'CITIZEN_BASIC',
846+
name: 'Lomake kuntalaiselle',
847+
published: true
848+
}).save()
849+
await Fixture.documentTemplate({
850+
type: 'LEOPS',
851+
name: 'Esiopetuksen oppimissuunnitelma 2023 (tämän ei pitäisi näkyä)',
852+
published: true
853+
}).save()
854+
})
855+
856+
test('unit supervisor can create child documents for any group', async () => {
857+
const user = await Fixture.employee().unitSupervisor(unit1.id).save()
858+
859+
const page = await Page.open({
860+
mockedTime: now,
861+
employeeCustomizations: {
862+
featureFlags: { citizenChildDocumentTypes: true }
863+
}
864+
})
865+
await employeeLogin(page, user)
866+
const unitPage = new UnitPage(page)
867+
await unitPage.navigateToUnit(unit1.id)
868+
const groupsPage = await unitPage.openGroupsPage()
869+
await groupsPage.selectPeriod('3 months')
870+
const groupCollapsible1 = await groupsPage.openGroupCollapsible(group1.id)
871+
const createChildDocumentsModal1 =
872+
await groupCollapsible1.openCreateChildDocumentsModal()
873+
await createChildDocumentsModal1.templateSelect.click()
874+
await createChildDocumentsModal1.templateSelect.assertOptions([
875+
template.name
876+
])
877+
await createChildDocumentsModal1.templateSelect.fillAndSelectItem(
878+
'',
879+
`create-child-documents-modal-select-template-${template.id}`
880+
)
881+
await createChildDocumentsModal1.childrenSelect.click()
882+
await createChildDocumentsModal1.childrenSelect.assertOptions([
883+
`${child1InGroup1.lastName} ${child1InGroup1.firstName}`,
884+
`${child2InGroup1.lastName} ${child2InGroup1.firstName}`,
885+
`${child3InGroup1.lastName} ${child3InGroup1.firstName}`
886+
])
887+
await createChildDocumentsModal1.childrenSelect.selectItem(
888+
child1InGroup1.id
889+
)
890+
await createChildDocumentsModal1.childrenSelect.selectItem(
891+
child3InGroup1.id
892+
)
893+
await createChildDocumentsModal1.click()
894+
await createChildDocumentsModal1.submitButton.click()
895+
await createChildDocumentsModal1.waitUntilHidden()
896+
897+
const expectedEmail = {
898+
from: 'Espoon Varhaiskasvatus <[email protected]>',
899+
900+
subject:
901+
'Uusi dokumentti eVakassa / Nytt dokument i eVaka / New document in eVaka'
902+
}
903+
await runJobs({ mockedTime: now })
904+
const emails1 = await getSentEmails()
905+
expect(
906+
emails1.map((email) => ({
907+
from: email.fromAddress,
908+
to: email.toAddress,
909+
subject: email.content.subject
910+
}))
911+
).toEqual([expectedEmail, expectedEmail])
912+
})
913+
914+
test('staff can create child documents for only own group', async () => {
915+
const user = await Fixture.employee()
916+
.staff(unit1.id)
917+
.withGroupAcl(group2.id)
918+
.save()
919+
920+
const page = await Page.open({
921+
mockedTime: now,
922+
employeeCustomizations: {
923+
featureFlags: { citizenChildDocumentTypes: true }
924+
}
925+
})
926+
await employeeLogin(page, user)
927+
const unitPage = new UnitPage(page)
928+
await unitPage.navigateToUnit(unit1.id)
929+
const groupsPage = await unitPage.openGroupsPage()
930+
const groupCollapsible1 = await groupsPage.openGroupCollapsible(group1.id)
931+
await groupCollapsible1.createChildDocumentsButton.waitUntilHidden()
932+
const groupCollapsible2 = await groupsPage.openGroupCollapsible(group2.id)
933+
const createChildDocumentsModal =
934+
await groupCollapsible2.openCreateChildDocumentsModal()
935+
await createChildDocumentsModal.templateSelect.click()
936+
await createChildDocumentsModal.templateSelect.assertOptions([
937+
template.name
938+
])
939+
await createChildDocumentsModal.templateSelect.fillAndSelectItem(
940+
'',
941+
`create-child-documents-modal-select-template-${template.id}`
942+
)
943+
await createChildDocumentsModal.childrenSelect.click()
944+
await createChildDocumentsModal.childrenSelect.assertOptions([
945+
`${child4InGroup2.lastName} ${child4InGroup2.firstName}`,
946+
`${child5InGroup2.lastName} ${child5InGroup2.firstName}`
947+
])
948+
await createChildDocumentsModal.childrenSelect.selectItem(child4InGroup2.id)
949+
await createChildDocumentsModal.click()
950+
await createChildDocumentsModal.submitButton.click()
951+
await createChildDocumentsModal.waitUntilHidden()
952+
953+
const expectedEmail = {
954+
from: 'Espoon Varhaiskasvatus <[email protected]>',
955+
956+
subject:
957+
'Uusi dokumentti eVakassa / Nytt dokument i eVaka / New document in eVaka'
958+
}
959+
await runJobs({ mockedTime: now })
960+
const emails1 = await getSentEmails()
961+
expect(
962+
emails1.map((email) => ({
963+
from: email.fromAddress,
964+
to: email.toAddress,
965+
subject: email.content.subject
966+
}))
967+
).toEqual([expectedEmail])
968+
})
969+
})

0 commit comments

Comments
 (0)