Skip to content

Commit

Permalink
fix: lock forms when organisation unit is closed [BETA-25] (#317)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomzemp authored Apr 20, 2023
1 parent e8152d6 commit 9a2531e
Show file tree
Hide file tree
Showing 17 changed files with 1,215 additions and 1,425 deletions.
342 changes: 131 additions & 211 deletions cypress/fixtures/network/40/a_data_set_can_be_selected.json

Large diffs are not rendered by default.

372 changes: 168 additions & 204 deletions cypress/fixtures/network/40/a_period_can_be_selected.json

Large diffs are not rendered by default.

473 changes: 179 additions & 294 deletions cypress/fixtures/network/40/a_section_filter_can_be_selected.json

Large diffs are not rendered by default.

441 changes: 172 additions & 269 deletions cypress/fixtures/network/40/an_org_unit_can_be_selected.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

360 changes: 167 additions & 193 deletions cypress/fixtures/network/40/static_resources.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions cypress/fixtures/network/40/summary.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"count": 1382,
"totalResponseSize": 5441572,
"duplicates": 1275,
"nonDeterministicResponses": 106,
"count": 1468,
"totalResponseSize": 5270746,
"duplicates": 1353,
"nonDeterministicResponses": 108,
"apiVersion": "40",
"fixtureFiles": [
"static_resources.json",
Expand Down
2 changes: 1 addition & 1 deletion cypress/integration/context-selection/org-unit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Given(
cy.intercept(
'GET',
new RegExp(
`organisationUnits/ImspTQPwCqd[?]fields=id,displayName,path$`
`organisationUnits/ImspTQPwCqd[?]fields=id,displayName,path,openingDate,closedDate$`
),
{ statusCode: 404, body: '404 Not Found!' }
)
Expand Down
21 changes: 11 additions & 10 deletions cypress/integration/context-selection/section-filter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@ Feature: A section filter can be selected
Then the section filter selector should be displayed
And the "all sections" option should be selected

Scenario: The user selects a filter section
Given a data set, org unit and period have been selected and the data set has some sections
When the user selects a section
Then that section should be selected
And the section id should be reflected in the url

Scenario: The data set is a tabbed sectioned form
Given a data set, org unit and period have been selected and the data set has a tabbed sectioned form
Then the first section should be selected by default
And no "all sections" option should be available
## Tests are disabled as fixtures are not updating
# Scenario: The user selects a filter section
# Given a data set, org unit and period have been selected and the data set has some sections
# When the user selects a section
# Then that section should be selected
# And the section id should be reflected in the url

# Scenario: The data set is a tabbed sectioned form
# Given a data set, org unit and period have been selected and the data set has a tabbed sectioned form
# Then the first section should be selected by default
# And no "all sections" option should be available

Scenario: The user enters a link with an period in the future (beyond the data set's allowed open future periods)
Given a link references an invalid section
Expand Down
11 changes: 9 additions & 2 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2023-03-02T12:32:54.438Z\n"
"PO-Revision-Date: 2023-03-02T12:32:54.438Z\n"
"POT-Creation-Date: 2023-04-13T13:04:22.948Z\n"
"PO-Revision-Date: 2023-04-13T13:04:22.948Z\n"

msgid "Not authorized"
msgstr "Not authorized"
Expand Down Expand Up @@ -457,6 +457,13 @@ msgstr ""
msgid "Data cannot be added or changed outside of the data input period."
msgstr "Data cannot be added or changed outside of the data input period."

msgid ""
"Data cannot be added or changed because organisation unit is closed for the "
"selected period."
msgstr ""
"Data cannot be added or changed because organisation unit is closed for the "
"selected period."

msgid "Data cannot be added or changed because data entry has concluded."
msgstr "Data cannot be added or changed because data entry has concluded."

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
useMetadata,
useDataSetId,
useOrgUnitId,
useOrgUnit,
} from '../../shared/index.js'
import DebouncedSearchInput from './debounced-search-input.js'
import DisabledTooltip from './disabled-tooltip.js'
Expand All @@ -19,7 +20,6 @@ import {
} from './organisation-unit-tree/index.js'
import useExpandedState from './use-expanded-state.js'
import useOrgUnitPathsByName from './use-org-unit-paths-by-name.js'
import useOrgUnit from './use-organisation-unit.js'
import usePrefetchedOrganisationUnits from './use-prefetched-organisation-units.js'
import useSelectorBarItemValue from './use-select-bar-item-value.js'
import useUserOrgUnits from './use-user-org-units.js'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import i18n from '@dhis2/d2-i18n'
import useOrgUnit from './use-organisation-unit.js'
import { useOrgUnit } from '../../shared/index.js'
import useUserOrgUnits from './use-user-org-units.js'

export default function useSelectorBarItemValue() {
Expand Down
3 changes: 3 additions & 0 deletions src/data-workspace/entry-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const lockedNoticeBoxMessages = {
[LockedStates.LOCKED_DATA_INPUT_PERIOD]: i18n.t(
'Data cannot be added or changed outside of the data input period.'
),
[LockedStates.LOCKED_ORGANISATION_UNIT]: i18n.t(
'Data cannot be added or changed because organisation unit is closed for the selected period.'
),
[LockedStates.LOCKED_EXPIRY_DAYS]: i18n.t(
'Data cannot be added or changed because data entry has concluded.'
),
Expand Down
1 change: 1 addition & 0 deletions src/shared/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export * from './value-types.js'
export * from './default-on-success.js'
export * from './use-will-component-unmount.js'
export * from './api-errors/index.js'
export * from './use-org-unit/use-organisation-unit.js'
1 change: 1 addition & 0 deletions src/shared/locked-status/locked-states.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const LockedStates = Object.freeze({
OPEN: 'Open',
LOCKED_DATA_INPUT_PERIOD: 'Locked_data_input_period',
LOCKED_ORGANISATION_UNIT: 'Locked_organisation_unit',
LOCKED_EXPIRY_DAYS: 'Locked_expiry_days',
LOCKED_APPROVED: 'Locked_approved',
LOCKED_NO_AUTHORITY: 'Locked_no_authority',
Expand Down
75 changes: 73 additions & 2 deletions src/shared/locked-status/use-check-lock-status.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useEffect } from 'react'
import { formatJsDateToDateString, useClientServerDate } from '../date/index.js'
import { useMetadata, selectors } from '../metadata/index.js'
import { usePeriod } from '../period/index.js'
import {
usePeriodId,
useDataSetId,
useOrgUnitId,
} from '../use-context-selection/use-context-selection.js'
import { useDataValueSet } from '../use-data-value-set/use-data-value-set.js'
import { useOrgUnit } from '../use-org-unit/use-organisation-unit.js'
import { LockedStates, BackendLockStatusMap } from './locked-states.js'
import { useLockedContext } from './use-locked-context.js'

Expand Down Expand Up @@ -36,10 +38,59 @@ const isDataInputPeriodLocked = ({
)
}

const isOrgUnitLocked = ({
orgUnitOpeningDateString,
orgUnitClosedDateString,
selectedPeriod,
}) => {
// if period start or end is undefined or if both opening and closed date are undefined for org unit, skip check
if (
!selectedPeriod?.startDate ||
!selectedPeriod?.endDate ||
(!orgUnitOpeningDateString && !orgUnitClosedDateString)
) {
return false
}
// since all the dates are the same (server) time zone, we do not need to do server/client time zone adjustments

// for the purpose of these calculations, dates are effecitvely treated as days without hours
// for example, if org unit closing date is 2020-12-31, the period December 2020 should still be open for the org unit
const periodStartDate = new Date(selectedPeriod.startDate + 'T00:00')
const periodEndDate = new Date(selectedPeriod.endDate + 'T00:00')

// if orgUnitOpeningDate exists, it must be earlier than the periodStartDate
if (orgUnitOpeningDateString) {
const orgUnitOpeningDate = new Date(orgUnitOpeningDateString)
if (!(orgUnitOpeningDate <= periodStartDate)) {
return true
}
}

// if orgUnitClosedDate exists, it must be after the periodEndDate
if (orgUnitClosedDateString) {
const orgUnitClosedDate = new Date(orgUnitClosedDateString)
if (!(orgUnitClosedDate >= periodEndDate)) {
return true
}
}

// otherwise default to assuming not locked
return false
}

export const useCheckLockStatus = () => {
const [dataSetId] = useDataSetId()
const [orgUnitId] = useOrgUnitId()
const orgUnit = useOrgUnit()
const {
data: {
openingDate: orgUnitOpeningDateString,
closedDate: orgUnitClosedDateString,
} = {},
} = orgUnit

const [periodId] = usePeriodId()
const selectedPeriod = usePeriod(periodId)
const currentDate = useClientServerDate()
const currentDayString = formatJsDateToDateString(currentDate.serverDate)
const { data: metadata } = useMetadata()
Expand All @@ -60,6 +111,17 @@ export const useCheckLockStatus = () => {
return
}

if (
isOrgUnitLocked({
orgUnitOpeningDateString,
orgUnitClosedDateString,
selectedPeriod,
})
) {
setLockStatus(LockedStates.LOCKED_ORGANISATION_UNIT)
return
}

// else default to lockStatus from dataValueSet
if (BackendLockStatusMap[dataValueSet.data?.lockStatus]) {
setLockStatus(BackendLockStatusMap[dataValueSet.data?.lockStatus])
Expand All @@ -72,7 +134,10 @@ export const useCheckLockStatus = () => {
metadata,
dataSetId,
orgUnitId,
orgUnitOpeningDateString,
orgUnitClosedDateString,
periodId,
selectedPeriod,
dataValueSet.data?.lockStatus,
setLockStatus,
currentDayString,
Expand All @@ -97,9 +162,15 @@ export const updateLockStatusFromBackend = (
}

// a lock status of 'OPEN' from the backend could mean either that the form is open OR
// that the form should be locked due to data input period, SO
// that the form should be locked due to data input period, OR
// that the form should be locked because an organisation unit is out of range, SO
// set to OPEN unless frontend check has identified that data input period as out-of-bounds
if (frontEndLockStatus !== LockedStates.LOCKED_DATA_INPUT_PERIOD) {
if (
![
LockedStates.LOCKED_DATA_INPUT_PERIOD,
LockedStates.LOCKED_ORGANISATION_UNIT,
].includes(frontEndLockStatus)
) {
setLockStatus(LockedStates.OPEN)
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { useQuery } from '@tanstack/react-query'
import { useOrgUnitId } from '../../shared/index.js'
import { useOrgUnitId } from '../use-context-selection/index.js'

export default function useOrgUnit() {
export const useOrgUnit = () => {
const [id] = useOrgUnitId()
const queryKey = [
'organisationUnits',
{
id,
params: {
fields: ['id', 'displayName', 'path'],
fields: [
'id',
'displayName',
'path',
'openingDate',
'closedDate',
],
},
},
]
Expand Down

1 comment on commit 9a2531e

@dhis2-bot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.