Skip to content

fix(calendar): dragging a task with an existing Compliance row creates a duplicate tile instead of moving #954

Description

@renemadsen

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:

  1. A tile from the compliance loopCompliance.Deadline = originalDate → tile on old date.
  2. A tile from the recurrence expansion loopplanning.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.csMoveTask 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:

  1. Navigate to /plugins/backend-configuration-pn/calendar.
  2. Create a non-recurring (or any-repeat) task on any board. Note the date it is placed on (e.g. Thursday June 4).
  3. 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).
  4. On the web calendar, drag the task from its current date to a new date (e.g. Friday June 5).
  5. If prompted with a scope dialog, select "All in series". Confirm.
  6. 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)

  1. Create a task and confirm it appears on date A.
  2. 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).
  3. Drag the task from date A to date B (scope = all).
  4. Assert exactly one tile is visible for this task, on date B.
  5. Assert no tile for this task is visible on date A.

C# integration test

In BackendConfiguration.Test:

  1. Seed an ARP + Planning + a Compliance row with Deadline = 2026-06-04.
  2. Call MoveTask with newDate = "2026-06-05", scope = "all".
  3. Assert the Compliance.Deadline has been updated to 2026-06-05.
  4. Call GetTasksForWeek for the week of June 1–7.
  5. Assert exactly one task entry is returned, on June 5 — not two entries.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions