diff --git a/src/Command/KimaiImporterCommand.php b/src/Command/KimaiImporterCommand.php index 2a88260f..b0187c4e 100644 --- a/src/Command/KimaiImporterCommand.php +++ b/src/Command/KimaiImporterCommand.php @@ -81,15 +81,14 @@ class KimaiImporterCommand extends Command * @var Activity[] */ protected $activities = []; - /** - * activityId => activity[] - * @var array - */ - protected $unassignedActivities = []; /** * @var bool */ protected $debug = false; + /** + * @var array + */ + protected $oldActivities = []; /** * @param UserPasswordEncoderInterface $encoder @@ -704,16 +703,32 @@ class KimaiImporterCommand extends Command { $counter = 0; $entityManager = $this->getDoctrine()->getManager(); + + // remember which activity has at least one assigned project $oldActivityMapping = []; foreach ($activityToProject as $mapping) { - $oldActivityMapping[$mapping['activityID']] = $mapping['projectID']; + $oldActivityMapping[$mapping['activityID']][] = $mapping['projectID']; } + // create global activities foreach ($activities as $oldActivity) { + $this->oldActivities[$oldActivity['activityID']] = $oldActivity; if (isset($oldActivityMapping[$oldActivity['activityID']])) { - $projectId = $oldActivityMapping[$oldActivity['activityID']]; - $project = null; + continue; + } + $this->createActivity($io, $entityManager, $oldActivity, $fixedRates, $rates, null); + ++$counter; + } + + $io->success('Created global activities: ' . $counter); + + // create project specific activities + foreach ($activities as $oldActivity) { + if (!isset($oldActivityMapping[$oldActivity['activityID']])) { + continue; + } + foreach ($oldActivityMapping[$oldActivity['activityID']] as $projectId) { if (!isset($this->projects[$projectId])) { throw new \Exception( 'Invalid project linked to activity ' . $oldActivity['name'] . ': ' . $projectId @@ -722,11 +737,8 @@ class KimaiImporterCommand extends Command $project = $this->projects[$projectId]; - $this->unassignedActivities[$oldActivity['activityID']] = $oldActivity; - $this->createActivity($io, $entityManager, $project, $oldActivity, $fixedRates, $rates); + $this->createActivity($io, $entityManager, $oldActivity, $fixedRates, $rates, $project); ++$counter; - } else { - $this->unassignedActivities[$oldActivity['activityID']] = $oldActivity; } } @@ -736,24 +748,27 @@ class KimaiImporterCommand extends Command /** * @param SymfonyStyle $io * @param ObjectManager $entityManager - * @param Project $project * @param array $oldActivity * @param array $fixedRates * @param array $rates + * @param Project $project * @return Activity * @throws \Exception */ protected function createActivity( SymfonyStyle $io, ObjectManager $entityManager, - Project $project, array $oldActivity, array $fixedRates, - array $rates + array $rates, + ?Project $project ) { + $activityId = $oldActivity['activityID']; - if (isset($this->activities[$activityId][$project->getId()])) { - return $this->activities[$activityId][$project->getId()]; + $projectId = null !== $project ? $project->getId() : null; + + if (isset($this->activities[$activityId][$projectId])) { + return $this->activities[$activityId][$projectId]; } $isActive = (bool) $oldActivity['visible'] && !(bool) $oldActivity['trash']; @@ -775,7 +790,7 @@ class KimaiImporterCommand extends Command if ($fixedRow['activityID'] === null) { continue; } - if ($fixedRow['projectID'] !== null && $fixedRow['projectID'] !== $project->getId()) { + if ($fixedRow['projectID'] !== null && $fixedRow['projectID'] !== $projectId) { continue; } @@ -788,7 +803,7 @@ class KimaiImporterCommand extends Command if ($ratesRow['userID'] !== null || $ratesRow['activityID'] === null) { continue; } - if ($ratesRow['projectID'] !== null && $ratesRow['projectID'] !== $project->getId()) { + if ($ratesRow['projectID'] !== null && $ratesRow['projectID'] !== $projectId) { continue; } @@ -815,7 +830,7 @@ class KimaiImporterCommand extends Command if (!isset($this->activities[$activityId])) { $this->activities[$activityId] = []; } - $this->activities[$activityId][$project->getId()] = $activity; + $this->activities[$activityId][$projectId] = $activity; return $activity; } @@ -872,18 +887,22 @@ class KimaiImporterCommand extends Command continue; } + $customerId = $project->getCustomer()->getId(); + if (isset($this->activities[$activityId][$projectId])) { $activity = $this->activities[$activityId][$projectId]; + } elseif (isset($this->activities[$activityId][null])) { + $activity = $this->activities[$activityId][null]; } - if (null === $activity && isset($this->unassignedActivities[$activityId])) { - $oldActivity = $this->unassignedActivities[$activityId]; - $activity = $this->createActivity($io, $entityManager, $project, $oldActivity, $fixedRates, $rates); + if (null === $activity && isset($this->oldActivities[$activityId])) { + $oldActivity = $this->oldActivities[$activityId]; + $activity = $this->createActivity($io, $entityManager, $oldActivity, $fixedRates, $rates, $project); ++$activityCounter; } if (null === $activity) { - $io->error('Could not create timesheet record, missing activity with ID: ' . $activityId); + $io->error('Could not create timesheet record, missing activity with ID: ' . $activityId . '/' . $projectId . '/' . $customerId); continue; } @@ -904,7 +923,7 @@ class KimaiImporterCommand extends Command if ($timesheet->getFixedRate() !== null) { $timesheet->setRate($timesheet->getFixedRate()); } elseif ($timesheet->getHourlyRate() !== null) { - $rate = $timesheet->getHourlyRate(); + $hourlyRate = $timesheet->getHourlyRate(); $rate = (float) $hourlyRate * ($duration / 3600); $timesheet->setRate(round($rate, 2)); } @@ -916,6 +935,7 @@ class KimaiImporterCommand extends Command ->setEnd(new \DateTime('@' . $oldRecord['end'])) ->setDuration($duration) ->setActivity($activity) + ->setProject($project) ; if (!$this->validateImport($io, $timesheet)) { @@ -947,7 +967,7 @@ class KimaiImporterCommand extends Command $io->writeln(' (' . $counter . '/' . $total . ')'); if ($activityCounter > 0) { - $io->success('Created new (previously global) activities during timesheet import: ' . $activityCounter); + $io->success('Created new activities during timesheet import: ' . $activityCounter); } return $counter; diff --git a/src/Invoice/Renderer/RendererTrait.php b/src/Invoice/Renderer/RendererTrait.php index 5adfacbc..79e142d2 100644 --- a/src/Invoice/Renderer/RendererTrait.php +++ b/src/Invoice/Renderer/RendererTrait.php @@ -135,7 +135,7 @@ trait RendererTrait } $activity = $timesheet->getActivity(); - $project = $activity->getProject(); + $project = $timesheet->getProject(); $customer = $project->getCustomer(); return [ diff --git a/tests/Invoice/Renderer/AbstractRendererTest.php b/tests/Invoice/Renderer/AbstractRendererTest.php index 449e3a23..0c61bd5c 100644 --- a/tests/Invoice/Renderer/AbstractRendererTest.php +++ b/tests/Invoice/Renderer/AbstractRendererTest.php @@ -210,6 +210,7 @@ abstract class AbstractRendererTest extends KernelTestCase ->setRate(293.27) ->setUser($user1) ->setActivity($activity) + ->setProject($project) ->setBegin(new \DateTime()) ->setEnd(new \DateTime()) ;