-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathTtImportWorklogsCommand.php
More file actions
99 lines (81 loc) · 3.75 KB
/
Copy pathTtImportWorklogsCommand.php
File metadata and controls
99 lines (81 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<?php
/*
* Copyright (c) 2026 Netresearch DTT GmbH
* SPDX-License-Identifier: AGPL-3.0-only
*/
declare(strict_types=1);
namespace App\Command;
use App\Entity\TicketSystem;
use App\Entity\User;
use App\Enum\SyncRunStatus;
use App\Service\Sync\ImportWorklogsService;
use App\Service\Sync\SyncRunConsoleRenderer;
use DateTimeImmutable;
use Doctrine\Persistence\ManagerRegistry;
use Exception;
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Attribute\Option;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use function sprintf;
#[AsCommand(name: 'tt:import-worklogs', description: 'Import Jira worklogs as pre-synced entries (ADR-023)')]
class TtImportWorklogsCommand extends Command
{
public function __construct(
private readonly ImportWorklogsService $importWorklogsService,
private readonly ManagerRegistry $managerRegistry,
private readonly SyncRunConsoleRenderer $syncRunConsoleRenderer,
) {
parent::__construct();
}
/**
* @param list<string> $users
*/
public function __invoke(
#[Argument(description: 'TimeTracker username whose Jira token performs the read', name: 'username')]
string $username,
#[Argument(description: 'Ticket system ID', name: 'ticket-system')]
string $ticketSystem,
InputInterface $input,
OutputInterface $output,
#[Option(description: 'Start date (Y-m-d); default: first day of current month', name: 'from')]
?string $from = null,
#[Option(description: 'End date (Y-m-d); default: today', name: 'to')]
?string $to = null,
#[Option(description: 'Only import for these TT usernames (repeatable); default: everyone (shadow users created for unknowns)', name: 'user')]
array $users = [],
#[Option(description: 'Activity ID assigned to imported entries (required)', name: 'default-activity')]
?string $defaultActivity = null,
#[Option(description: 'Preview only: counters and parked items, no writes', name: 'dry-run')]
bool $dryRun = false,
): int {
$symfonyStyle = new SymfonyStyle($input, $output);
if (null === $defaultActivity || '' === $defaultActivity) {
$symfonyStyle->error('--default-activity=<ID> is required (activity assigned to imported entries)');
return 1;
}
$user = $this->managerRegistry->getRepository(User::class)->findOneBy(['username' => $username]);
if (!$user instanceof User) {
$symfonyStyle->error('User not found: ' . $username);
return 1;
}
$system = $this->managerRegistry->getRepository(TicketSystem::class)->find((int) $ticketSystem);
if (!$system instanceof TicketSystem) {
$symfonyStyle->error('Ticket system not found: ' . $ticketSystem);
return 1;
}
try {
$fromDate = null !== $from ? new DateTimeImmutable($from) : new DateTimeImmutable('first day of this month');
$toDate = null !== $to ? new DateTimeImmutable($to) : new DateTimeImmutable('today');
} catch (Exception) {
$symfonyStyle->error(sprintf('Invalid date in --from/--to (expected Y-m-d): %s / %s', $from ?? '-', $to ?? '-'));
return 1;
}
$syncRun = $this->importWorklogsService->import($user, $system, $fromDate, $toDate, (int) $defaultActivity, $users, $dryRun);
$this->syncRunConsoleRenderer->render($symfonyStyle, $syncRun, 'Import');
return SyncRunStatus::COMPLETED === $syncRun->getStatus() ? Command::SUCCESS : 1;
}
}