diff --git a/appinfo/info.xml b/appinfo/info.xml index 5c4db0c..959f224 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -28,7 +28,7 @@ This app lets every user configure their own Deck automation workflows from Pers A background job periodically evaluates all enabled workflows and moves cards whose due date has passed, using Deck's own internal PHP classes only (no HTTP/OCS calls). ]]> - 34.0.1 + 34.0.2 agpl Patrick Niebeling WorkflowDeckAutomation diff --git a/lib/Service/WorkflowRunner.php b/lib/Service/WorkflowRunner.php index d40bd61..2808ada 100644 --- a/lib/Service/WorkflowRunner.php +++ b/lib/Service/WorkflowRunner.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace OCA\WorkflowDeckAutomation\Service; +use DateTimeInterface; use OCA\Deck\Db\Card; use OCA\WorkflowDeckAutomation\Db\Workflow; use OCA\WorkflowDeckAutomation\Db\WorkflowMapper; @@ -165,8 +166,10 @@ class WorkflowRunner { // and the workflow wants a mail — this is decoration, not a check. $targets = null; + $now = $this->timeFactory->getDateTime(); + foreach ($cards as $card) { - if (!self::isOverdue($card->getDaysUntilDue())) { + if (!self::isOverdue($card->getDuedate(), $now)) { continue; } @@ -319,8 +322,17 @@ class WorkflowRunner { } } - public static function isOverdue(?int $daysUntilDue): bool { - return $daysUntilDue !== null && $daysUntilDue < 0; + /** + * Compares the card's actual due timestamp against $now instead of Deck's own + * Card::getDaysUntilDue(), which truncates both sides to midnight before diffing + * (DateInterval's %a is a whole-day count) and therefore reports 0 - not overdue - + * for any card whose due time has already passed today. That silently held back + * every card for up to 24h after it actually fell due; comparing the raw datetime + * instead matches what Deck's own UI shows (e.g. "vor 2 Stunden") and has no + * day-rounding step to get wrong. + */ + public static function isOverdue(?DateTimeInterface $duedate, DateTimeInterface $now): bool { + return $duedate !== null && $duedate < $now; } /** diff --git a/package.json b/package.json index 16a3a1e..de0f383 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "workflow_deck_automation", - "version": "34.0.1", + "version": "34.0.2", "private": true, "type": "module", "description": "Automates moving overdue Deck cards between stacks, configurable per user.", diff --git a/tests/Unit/Service/WorkflowRunnerFilterTest.php b/tests/Unit/Service/WorkflowRunnerFilterTest.php index e9d553b..93b01b3 100644 --- a/tests/Unit/Service/WorkflowRunnerFilterTest.php +++ b/tests/Unit/Service/WorkflowRunnerFilterTest.php @@ -4,22 +4,35 @@ declare(strict_types=1); namespace OCA\WorkflowDeckAutomation\Tests\Unit\Service; +use DateTimeImmutable; use OCA\WorkflowDeckAutomation\Service\WorkflowRunner; use PHPUnit\Framework\TestCase; class WorkflowRunnerFilterTest extends TestCase { public function testIsOverdueReturnsFalseWithoutDueDate(): void { - $this->assertFalse(WorkflowRunner::isOverdue(null)); + $this->assertFalse(WorkflowRunner::isOverdue(null, new DateTimeImmutable('2026-01-15 12:00:00'))); } public function testIsOverdueReturnsFalseForFutureDueDate(): void { - $this->assertFalse(WorkflowRunner::isOverdue(0)); - $this->assertFalse(WorkflowRunner::isOverdue(3)); + $now = new DateTimeImmutable('2026-01-15 12:00:00'); + $this->assertFalse(WorkflowRunner::isOverdue($now->modify('+1 hour'), $now)); + $this->assertFalse(WorkflowRunner::isOverdue($now->modify('+3 days'), $now)); } public function testIsOverdueReturnsTrueForPastDueDate(): void { - $this->assertTrue(WorkflowRunner::isOverdue(-1)); - $this->assertTrue(WorkflowRunner::isOverdue(-30)); + $now = new DateTimeImmutable('2026-01-15 12:00:00'); + $this->assertTrue(WorkflowRunner::isOverdue($now->modify('-1 hour'), $now)); + $this->assertTrue(WorkflowRunner::isOverdue($now->modify('-30 days'), $now)); + } + + public function testIsOverdueReturnsTrueForADueTimeEarlierTheSameDay(): void { + // Regression: comparing whole calendar days (as Deck's own + // Card::getDaysUntilDue() does) reports a card due earlier today as + // "0 days until due", not overdue, until the calendar date rolls + // over - holding every card back for up to 24h after it actually + // fell due. isOverdue() must compare the real timestamps instead. + $now = new DateTimeImmutable('2026-01-15 12:00:00'); + $this->assertTrue(WorkflowRunner::isOverdue(new DateTimeImmutable('2026-01-15 06:00:00'), $now)); } public function testNoFiltersMatchesAnyCard(): void {