Summary
When a task that has an active Compliance record is dragged to a new date, the calendar shows two tiles — one on the original date and one on the new date — instead of one tile on the new date.
This affects any task that has been opened by a device worker (which creates a Compliance row with a Deadline pointing to the original date).
Root Cause (already analysed)
BackendConfigurationCalendarService.MoveTask scope = "all" updates:
arp.StartDate = newDate
planning.StartDate = newDate
But it does not update the Compliance.Deadline field. The existing Compliance row keeps Deadline = originalDate.
GetTasksForWeek then emits both:
- A tile from the compliance loop —
Compliance.Deadline = originalDate → tile on old date.
- A tile from the recurrence expansion loop —
planning.StartDate = newDate → tile on new date.
The dedup gate (complianceDateSet, line ~296) blocks a recurrence-loop tile only when a compliance exists for the same date. Since originalDate ≠ newDate, both tiles pass the gate.
Fix required in MoveTask scope = "all" (and "thisAndFollowing" where applicable):
After updating arp.StartDate = newDate, query for active (non-Removed) Compliance rows for this planning:
var openCompliances = await dbContext.Compliances
.Where(c => c.PlanningId == arp.ItemPlanningId
&& c.WorkflowState != Constants.WorkflowStates.Removed)
.ToListAsync();
foreach (var c in openCompliances)
c.Deadline = newDate;
Files to fix:
BackendConfigurationCalendarService.cs — MoveTask method, scope = "all" branch (lines ~1910–1977) and "thisAndFollowing" branch (lines ~1772–1909).
Steps to reproduce
Use Playwright against http://localhost:4200. Login: <your-admin-email> / <your-local-admin-password>.
Note: The duplicate only appears after a Compliance row exists for the task — i.e. after the task has been submitted/opened on a device, which creates the row. If no device has touched the task, the duplicate will not appear. To reproduce without a device:
- Alternatively, you can verify by checking after any drag whether the calendar reloads and shows a tile on the original date alongside the new date.
Reproduction steps:
- Navigate to
/plugins/backend-configuration-pn/calendar.
- Create a non-recurring (or any-repeat) task on any board. Note the date it is placed on (e.g. Thursday June 4).
- Wait for or trigger a compliance case to be created (the task must have been opened from a device, or a case worker has interacted with it — this creates the stale
Compliance.Deadline row).
- On the web calendar, drag the task from its current date to a new date (e.g. Friday June 5).
- If prompted with a scope dialog, select "All in series". Confirm.
- Observe the calendar after reload.
Expected: One tile on Friday June 5; nothing on Thursday June 4.
Actual: Tiles appear on both Thursday June 4 and Friday June 5.
How to verify the fix
Playwright test (Angular e2e)
- Create a task and confirm it appears on date A.
- Via the test setup, insert a
Compliance row with Deadline = date A for this task's PlanningId (or simulate a device case opening if a helper exists).
- Drag the task from date A to date B (scope = all).
- Assert exactly one tile is visible for this task, on date B.
- Assert no tile for this task is visible on date A.
C# integration test
In BackendConfiguration.Test:
- Seed an ARP + Planning + a
Compliance row with Deadline = 2026-06-04.
- Call
MoveTask with newDate = "2026-06-05", scope = "all".
- Assert the
Compliance.Deadline has been updated to 2026-06-05.
- Call
GetTasksForWeek for the week of June 1–7.
- Assert exactly one task entry is returned, on June 5 — not two entries.
Summary
When a task that has an active
Compliancerecord is dragged to a new date, the calendar shows two tiles — one on the original date and one on the new date — instead of one tile on the new date.This affects any task that has been opened by a device worker (which creates a
Compliancerow with aDeadlinepointing to the original date).Root Cause (already analysed)
BackendConfigurationCalendarService.MoveTaskscope ="all"updates:arp.StartDate = newDateplanning.StartDate = newDateBut it does not update the
Compliance.Deadlinefield. The existingCompliancerow keepsDeadline = originalDate.GetTasksForWeekthen emits both:Compliance.Deadline = originalDate→ tile on old date.planning.StartDate = newDate→ tile on new date.The dedup gate (
complianceDateSet, line ~296) blocks a recurrence-loop tile only when a compliance exists for the same date. SinceoriginalDate ≠ newDate, both tiles pass the gate.Fix required in
MoveTaskscope ="all"(and"thisAndFollowing"where applicable):After updating
arp.StartDate = newDate, query for active (non-Removed)Compliancerows for this planning:Files to fix:
BackendConfigurationCalendarService.cs—MoveTaskmethod, scope ="all"branch (lines ~1910–1977) and"thisAndFollowing"branch (lines ~1772–1909).Steps to reproduce
Use Playwright against
http://localhost:4200. Login:<your-admin-email>/<your-local-admin-password>.Reproduction steps:
/plugins/backend-configuration-pn/calendar.Compliance.Deadlinerow).Expected: One tile on Friday June 5; nothing on Thursday June 4.
Actual: Tiles appear on both Thursday June 4 and Friday June 5.
How to verify the fix
Playwright test (Angular e2e)
Compliancerow withDeadline = date Afor this task'sPlanningId(or simulate a device case opening if a helper exists).C# integration test
In
BackendConfiguration.Test:Compliancerow withDeadline = 2026-06-04.MoveTaskwithnewDate = "2026-06-05",scope = "all".Compliance.Deadlinehas been updated to2026-06-05.GetTasksForWeekfor the week of June 1–7.