added fixed-rate and hourly-rate for customer, project and activity (#304)

This commit is contained in:
Kevin Papst
2018-09-06 23:37:25 +02:00
committed by GitHub
parent 6163f33abf
commit 8cae5e8b3f
32 changed files with 1173 additions and 154 deletions

View File

@@ -168,6 +168,8 @@ class KimaiImporterCommand extends Command
$activities = null;
$records = null;
$activityToProject = null;
$fixedRates = null;
$rates = null;
$bytesStart = memory_get_usage(true);
@@ -219,6 +221,22 @@ class KimaiImporterCommand extends Command
return;
}
try {
$fixedRates = $this->fetchAllFromImport('fixedRates');
} catch (\Exception $ex) {
$io->error('Failed to load fixedRates: ' . $ex->getMessage());
return;
}
try {
$rates = $this->fetchAllFromImport('rates');
} catch (\Exception $ex) {
$io->error('Failed to load rates: ' . $ex->getMessage());
return;
}
$bytesCached = memory_get_usage(true);
$io->success('Fetched Kimai v1 data, trying to import now ...');
@@ -246,7 +264,7 @@ class KimaiImporterCommand extends Command
}
try {
$counter = $this->importProjects($io, $projects);
$counter = $this->importProjects($io, $projects, $fixedRates, $rates);
$allImports += $counter;
$io->success('Imported projects: ' . $counter);
} catch (\Exception $ex) {
@@ -256,7 +274,7 @@ class KimaiImporterCommand extends Command
}
try {
$counter = $this->importActivities($io, $activities, $activityToProject);
$counter = $this->importActivities($io, $activities, $activityToProject, $fixedRates, $rates);
$allImports += $counter;
$io->success('Imported activities: ' . $counter);
} catch (\Exception $ex) {
@@ -266,7 +284,7 @@ class KimaiImporterCommand extends Command
}
try {
$counter = $this->importTimesheetRecords($io, $records);
$counter = $this->importTimesheetRecords($io, $records, $fixedRates, $rates);
$allImports += $counter;
$io->success('Imported timesheet records: ' . $counter);
} catch (\Exception $ex) {
@@ -275,10 +293,6 @@ class KimaiImporterCommand extends Command
return;
}
// TODO support fixedRates (projectID, activityID, rate)
// TODO support rates (userID, projectID, activityID, rate)
// TODO dump yaml config from configuration (adminmail, currency_name, date_format_0, language, roundPrecision)
// TODO support preferences (ui.lang, timezone)
// TODO support expenses - new database required
$bytesImported = memory_get_usage(true);
@@ -294,8 +308,8 @@ class KimaiImporterCommand extends Command
}
/**
* Checks if the ghiven database connection for import has an underlying database with a compatible structure.
* This is checked againstto the Kimai version and database revision.
* Checks if the given database connection for import has an underlying database with a compatible structure.
* This is checked against the Kimai version and database revision.
*
* @param SymfonyStyle $io
* @param $requiredVersion
@@ -508,8 +522,8 @@ class KimaiImporterCommand extends Command
* ["phone"]=> NULL
* ["fax"]=> NULL
* ["mobile"]=> NULL
* --- ["mail"]=> NULL
* --- ["homepage"]=> NULL
* ["mail"]=> NULL
* ["homepage"]=> NULL
* ["trash"]=> string(1) "0"
* ["timezone"]=> string(13) "Europe/Berlin"
*
@@ -538,7 +552,9 @@ class KimaiImporterCommand extends Command
->setComment($oldCustomer['comment'])
->setCompany($oldCustomer['company'])
->setFax($oldCustomer['fax'])
->setHomepage($oldCustomer['homepage'])
->setMobile($oldCustomer['mobile'])
->setMail($oldCustomer['mail'])
->setPhone($oldCustomer['phone'])
->setContact($oldCustomer['contact'])
->setAddress($oldCustomer['street'] . PHP_EOL . $oldCustomer['zipcode'] . ' ' . $oldCustomer['city'])
@@ -586,10 +602,12 @@ class KimaiImporterCommand extends Command
*
* @param SymfonyStyle $io
* @param array $projects
* @param array $fixedRates
* @param array $rates
* @return int
* @throws \Exception
*/
protected function importProjects(SymfonyStyle $io, $projects)
protected function importProjects(SymfonyStyle $io, $projects, array $fixedRates, array $rates)
{
$counter = 0;
$entityManager = $this->getDoctrine()->getManager();
@@ -611,6 +629,24 @@ class KimaiImporterCommand extends Command
->setVisible($isActive)
;
foreach ($fixedRates as $fixedRow) {
if ($fixedRow['activityID'] !== null || $fixedRow['projectID'] === null) {
continue;
}
if ($fixedRow['projectID'] == $oldProject['projectID']) {
$project->setFixedRate($fixedRow['rate']);
}
}
foreach ($rates as $ratesRow) {
if ($ratesRow['userID'] !== null || $ratesRow['activityID'] !== null || $ratesRow['projectID'] === null) {
continue;
}
if ($ratesRow['projectID'] == $oldProject['projectID']) {
$project->setHourlyRate($ratesRow['rate']);
}
}
if (!$this->validateImport($io, $project)) {
throw new \Exception('Failed to validate project: ' . $project->getName());
}
@@ -654,10 +690,12 @@ class KimaiImporterCommand extends Command
* @param SymfonyStyle $io
* @param array $activities
* @param array $activityToProject
* @param array $fixedRates
* @param array $rates
* @return int
* @throws \Exception
*/
protected function importActivities(SymfonyStyle $io, array $activities, array $activityToProject)
protected function importActivities(SymfonyStyle $io, array $activities, array $activityToProject, array $fixedRates, array $rates)
{
$counter = 0;
$entityManager = $this->getDoctrine()->getManager();
@@ -680,7 +718,7 @@ class KimaiImporterCommand extends Command
$project = $this->projects[$projectId];
$this->unassignedActivities[$oldActivity['activityID']] = $oldActivity;
$this->createActivity($io, $entityManager, $project, $oldActivity);
$this->createActivity($io, $entityManager, $project, $oldActivity, $fixedRates, $rates);
++$counter;
} else {
$this->unassignedActivities[$oldActivity['activityID']] = $oldActivity;
@@ -695,6 +733,8 @@ class KimaiImporterCommand extends Command
* @param ObjectManager $entityManager
* @param Project $project
* @param array $oldActivity
* @param array $fixedRates
* @param array $rates
* @return Activity
* @throws \Exception
*/
@@ -702,7 +742,9 @@ class KimaiImporterCommand extends Command
SymfonyStyle $io,
ObjectManager $entityManager,
Project $project,
array $oldActivity
array $oldActivity,
array $fixedRates,
array $rates
) {
$activityId = $oldActivity['activityID'];
if (isset($this->activities[$activityId][$project->getId()])) {
@@ -724,6 +766,33 @@ class KimaiImporterCommand extends Command
->setProject($project)
;
foreach ($fixedRates as $fixedRow) {
if ($fixedRow['activityID'] === null) {
continue;
}
if ($fixedRow['projectID'] !== null && $fixedRow['projectID'] !== $project->getId()) {
continue;
}
if ($fixedRow['activityID'] == $oldActivity['activityID']) {
$activity->setFixedRate($fixedRow['rate']);
}
}
foreach ($rates as $ratesRow) {
if ($ratesRow['userID'] !== null || $ratesRow['activityID'] === null) {
continue;
}
if ($ratesRow['projectID'] !== null && $ratesRow['projectID'] !== $project->getId()) {
continue;
}
if ($ratesRow['activityID'] == $oldActivity['activityID']) {
$activity->setHourlyRate($ratesRow['rate']);
}
}
if (!$this->validateImport($io, $activity)) {
throw new \Exception('Failed to validate activity: ' . $activity->getName());
}
@@ -772,14 +841,19 @@ class KimaiImporterCommand extends Command
*
* @param SymfonyStyle $io
* @param array $records
* @param array $fixedRates
* @param array $rates
* @return int
* @throws \Exception
*/
protected function importTimesheetRecords(SymfonyStyle $io, array $records)
protected function importTimesheetRecords(SymfonyStyle $io, array $records, array $fixedRates, array $rates)
{
$counter = 0;
$activityCounter = 0;
$entityManager = $this->getDoctrine()->getManager();
$total = count($records);
$io->writeln('Importing timesheets, please wait');
foreach ($records as $oldRecord) {
$activity = null;
@@ -800,7 +874,7 @@ class KimaiImporterCommand extends Command
if (null === $activity && isset($this->unassignedActivities[$activityId])) {
$oldActivity = $this->unassignedActivities[$activityId];
$activity = $this->createActivity($io, $entityManager, $project, $oldActivity);
$activity = $this->createActivity($io, $entityManager, $project, $oldActivity, $fixedRates, $rates);
++$activityCounter;
}
@@ -811,14 +885,26 @@ class KimaiImporterCommand extends Command
$duration = $oldRecord['end'] - $oldRecord['start'];
$rate = $oldRecord['fixedRate'];
if ((empty($rate) || 0.00 == $rate) && !empty($oldRecord['rate'])) {
$hourlyRate = (float) $oldRecord['rate'];
$rate = (float) $hourlyRate * ($duration / 3600);
$rate = round($rate, 2);
$timesheet = new Timesheet();
$fixedRate = $oldRecord['fixedRate'];
if (!empty($fixedRate) && 0.00 != $fixedRate) {
$timesheet->setFixedRate($fixedRate);
}
$hourlyRate = $oldRecord['rate'];
if (!empty($hourlyRate) && 0.00 != $hourlyRate) {
$timesheet->setHourlyRate($hourlyRate);
}
if ($timesheet->getFixedRate() !== null) {
$timesheet->setRate($timesheet->getFixedRate());
} elseif ($timesheet->getHourlyRate() !== null) {
$rate = $timesheet->getHourlyRate();
$rate = (float) $hourlyRate * ($duration / 3600);
$timesheet->setRate(round($rate, 2));
}
$timesheet = new Timesheet();
$timesheet
->setDescription($oldRecord['description'] ?: ($oldRecord['comment'] ?: null))
->setUser($this->users[$oldRecord['userID']])
@@ -826,7 +912,6 @@ class KimaiImporterCommand extends Command
->setEnd(new \DateTime('@' . $oldRecord['end']))
->setDuration($duration)
->setActivity($activity)
->setRate($rate)
;
if (!$this->validateImport($io, $timesheet)) {
@@ -845,13 +930,20 @@ class KimaiImporterCommand extends Command
$io->error('Reason: ' . $ex->getMessage());
}
if (0 == $counter % 500) {
$io->writeln('Imported ' . $counter . ' timesheet records, import ongoing ...');
$io->write('.');
if (0 == $counter % 80) {
$io->writeln(' ('.$counter.'/'.$total.')');
$entityManager->clear(Timesheet::class);
}
}
for ($i = 0; $i < 80-($counter%80); $i++) {
$io->write(' ');
}
$io->writeln(' ('.$counter.'/'.$total.')');
if ($activityCounter > 0) {
$io->success('Created new (previously unattached) activities during timesheet import: ' . $activityCounter);
$io->success('Created new (previously global) activities during timesheet import: ' . $activityCounter);
}
return $counter;