mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-10-08 05:43:18 +01:00
Compare commits
3 Commits
feature/cl
...
feature/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a504bcb878 | ||
|
|
556dfd39eb | ||
|
|
91fc4d779d |
@@ -44,7 +44,7 @@ class ClockifyProjectsImporter extends DefaultImporter
|
||||
'organization_id' => $this->organization->id,
|
||||
], [
|
||||
'color' => $this->colorService->getRandomColor(),
|
||||
'is_billable' => $record['Billability'] === 'Yes',
|
||||
'is_billable' => ($record['Billability'] ?? '') === 'Yes',
|
||||
'billable_rate' => $billableRateKey !== null && $record[$billableRateKey] !== '' ? (int) (((float) $record[$billableRateKey]) * 100) : null,
|
||||
'estimated_time' => isset($record['Estimated (h)']) && is_numeric($record['Estimated (h)']) ? (int) ($record['Estimated (h)'] * 3600) : null,
|
||||
'archived_at' => $record['Status'] === 'Archived' ? Carbon::now() : null,
|
||||
@@ -54,6 +54,7 @@ class ClockifyProjectsImporter extends DefaultImporter
|
||||
if ($tasksKey !== null && $record[$tasksKey] !== '') {
|
||||
$tasks = explode(', ', $record[$tasksKey]);
|
||||
foreach ($tasks as $task) {
|
||||
$this->checkTaskNameLength($task);
|
||||
$this->taskImportHelper->getKey([
|
||||
'name' => $task,
|
||||
'project_id' => $projectId,
|
||||
@@ -83,7 +84,6 @@ class ClockifyProjectsImporter extends DefaultImporter
|
||||
'Project',
|
||||
'Status',
|
||||
'Visibility',
|
||||
'Billability',
|
||||
];
|
||||
foreach ($requiredFields as $requiredField) {
|
||||
if (! in_array($requiredField, $header, true)) {
|
||||
|
||||
@@ -103,6 +103,7 @@ class ClockifyTimeEntriesImporter extends DefaultImporter
|
||||
}
|
||||
$taskId = null;
|
||||
if (! $isBreak && $taskKey !== null && $record[$taskKey] !== '') {
|
||||
$this->checkTaskNameLength($record[$taskKey]);
|
||||
$taskId = $this->taskImportHelper->getKey([
|
||||
'name' => $record[$taskKey],
|
||||
'project_id' => $projectId,
|
||||
|
||||
@@ -21,6 +21,8 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
abstract class DefaultImporter implements ImporterContract
|
||||
{
|
||||
protected const TASK_NAME_MAX_LENGTH = 500;
|
||||
|
||||
protected Organization $organization;
|
||||
|
||||
/**
|
||||
@@ -181,6 +183,16 @@ abstract class DefaultImporter implements ImporterContract
|
||||
$this->billableRateService = app(BillableRateService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ImportException
|
||||
*/
|
||||
protected function checkTaskNameLength(string $taskName): void
|
||||
{
|
||||
if (strlen($taskName) > self::TASK_NAME_MAX_LENGTH) {
|
||||
throw new ImportException('Task name ("'.$taskName.'") is too long, maximum length is '.self::TASK_NAME_MAX_LENGTH.' characters');
|
||||
}
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function getReport(): ReportDto
|
||||
{
|
||||
|
||||
@@ -113,6 +113,7 @@ class GenericTimeEntriesImporter extends DefaultImporter
|
||||
}
|
||||
$taskId = null;
|
||||
if ($record['task'] !== '') {
|
||||
$this->checkTaskNameLength($record['task']);
|
||||
$taskId = $this->taskImportHelper->getKey([
|
||||
'name' => $record['task'],
|
||||
'project_id' => $projectId,
|
||||
|
||||
@@ -92,6 +92,7 @@ class HarvestTimeEntriesImporter extends DefaultImporter
|
||||
}
|
||||
$taskId = null;
|
||||
if ($record['Task'] !== '') {
|
||||
$this->checkTaskNameLength($record['Task']);
|
||||
$taskId = $this->taskImportHelper->getKey([
|
||||
'name' => $record['Task'],
|
||||
'project_id' => $projectId,
|
||||
|
||||
@@ -199,6 +199,7 @@ class SolidtimeImporter extends DefaultImporter
|
||||
if ($projectId === null) {
|
||||
throw new Exception('Project does not exist');
|
||||
}
|
||||
$this->checkTaskNameLength($task['name']);
|
||||
$this->taskImportHelper->getKey([
|
||||
'name' => $task['name'],
|
||||
'project_id' => $projectId,
|
||||
|
||||
@@ -153,9 +153,16 @@ class TogglDataImporter extends DefaultImporter
|
||||
}
|
||||
foreach ($projectMembers as $projectMember) {
|
||||
$userId = $this->userImportHelper->getKeyByExternalIdentifier((string) $projectMember->user_id);
|
||||
if ($userId === null) {
|
||||
throw new Exception('User does not exist');
|
||||
}
|
||||
$memberId = $this->memberImportHelper->getKeyByExternalIdentifier($userId);
|
||||
if ($memberId === null) {
|
||||
throw new Exception('Member does not exist');
|
||||
}
|
||||
$this->projectMemberImportHelper->getKey([
|
||||
'project_id' => $projectId,
|
||||
'member_id' => $this->memberImportHelper->getKeyByExternalIdentifier($userId),
|
||||
'member_id' => $memberId,
|
||||
], [
|
||||
'user_id' => $userId,
|
||||
'billable_rate' => $projectMember->rate !== null ? (int) ($projectMember->rate * 100) : null,
|
||||
@@ -182,6 +189,7 @@ class TogglDataImporter extends DefaultImporter
|
||||
if ($projectId === null) {
|
||||
throw new Exception('Project does not exist');
|
||||
}
|
||||
$this->checkTaskNameLength($task->name);
|
||||
$this->taskImportHelper->getKey([
|
||||
'name' => $task->name,
|
||||
'project_id' => $projectId,
|
||||
|
||||
@@ -97,6 +97,7 @@ class TogglTimeEntriesImporter extends DefaultImporter
|
||||
}
|
||||
$taskId = null;
|
||||
if ($record['Task'] !== '') {
|
||||
$this->checkTaskNameLength($record['Task']);
|
||||
$taskId = $this->taskImportHelper->getKey([
|
||||
'name' => $record['Task'],
|
||||
'project_id' => $projectId,
|
||||
|
||||
4
resources/testfiles/clockify_projects_import_test_5.csv
Normal file
4
resources/testfiles/clockify_projects_import_test_5.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
"Project","Client","Status","Visibility","Tasks","Tracked (h)","Estimated (h)","Remaining (h)","Overage (h)","Progress(%)","Project members","Project manager","Note"
|
||||
"Project for Big Company","Big Company","Active","Public","Task 1, Task 2, Task 3","1.38","","","","","Constantin Graf","",""
|
||||
"Project without Client","","Active","Public","","0.00","","","","","Constantin Graf","",""
|
||||
"TEST","Big Company","Active","Public","","0.00","","","","","Constantin Graf","",""
|
||||
|
@@ -119,6 +119,24 @@ class ClockifyProjectsImporterTest extends ImporterTestAbstract
|
||||
);
|
||||
}
|
||||
|
||||
public function test_import_of_test_file_without_billability_column_defaults_to_not_billable(): void
|
||||
{
|
||||
// Arrange
|
||||
$organization = Organization::factory()->create();
|
||||
$timezone = 'Europe/Vienna';
|
||||
$importer = new ClockifyProjectsImporter;
|
||||
$importer->init($organization);
|
||||
// Some Clockify exports don't contain a "Billability" column.
|
||||
$data = Storage::disk('testfiles')->get('clockify_projects_import_test_5.csv');
|
||||
|
||||
// Act
|
||||
$importer->importData($data, $timezone);
|
||||
|
||||
// Assert
|
||||
$project = Project::query()->where('organization_id', $organization->id)->where('name', 'Project for Big Company')->firstOrFail();
|
||||
$this->assertFalse($project->is_billable);
|
||||
}
|
||||
|
||||
public function test_import_supports_activities_column_alias_for_tasks(): void
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -66,4 +66,27 @@ class GenericTimeEntriesImporterTest extends ImporterTestAbstract
|
||||
$this->assertSame(0, $report->projectsCreated);
|
||||
$this->assertSame(0, $report->clientsCreated);
|
||||
}
|
||||
|
||||
public function test_import_fails_if_task_name_is_too_long(): void
|
||||
{
|
||||
// Arrange
|
||||
$organization = Organization::factory()->create();
|
||||
$timezone = 'Europe/Vienna';
|
||||
$importer = new GenericTimeEntriesImporter;
|
||||
$importer->init($organization);
|
||||
$taskName = str_repeat('a', 501);
|
||||
$data = "description,billable,client,project,tags,start,end,task,user_name,user_email\n".
|
||||
'"Working hard","true","Big Company","Project for Big Company","","2024-03-04T09:23:00Z","2024-03-04T10:23:01Z","'.$taskName.'","Peter Tester","peter.test@email.test"';
|
||||
|
||||
// Act
|
||||
try {
|
||||
$importer->importData($data, $timezone);
|
||||
} catch (ImportException $e) {
|
||||
// Assert
|
||||
$this->assertSame('Task name ("'.$taskName.'") is too long, maximum length is 500 characters', $e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
$this->fail();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user