Compare commits

..

2 Commits

Author SHA1 Message Date
Constantin Graf
cf7bc076cf Add placeholder paddle api key 2026-09-21 21:59:21 +02:00
Constantin Graf
f6b6b0a467 Add GitHub action for phpunit tests with extensions 2026-09-21 21:59:21 +02:00
11 changed files with 3 additions and 73 deletions

View File

@@ -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,7 +54,6 @@ 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,
@@ -84,6 +83,7 @@ class ClockifyProjectsImporter extends DefaultImporter
'Project',
'Status',
'Visibility',
'Billability',
];
foreach ($requiredFields as $requiredField) {
if (! in_array($requiredField, $header, true)) {

View File

@@ -103,7 +103,6 @@ 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,

View File

@@ -21,8 +21,6 @@ use Illuminate\Database\Eloquent\Builder;
abstract class DefaultImporter implements ImporterContract
{
protected const TASK_NAME_MAX_LENGTH = 500;
protected Organization $organization;
/**
@@ -183,16 +181,6 @@ 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
{

View File

@@ -113,7 +113,6 @@ class GenericTimeEntriesImporter extends DefaultImporter
}
$taskId = null;
if ($record['task'] !== '') {
$this->checkTaskNameLength($record['task']);
$taskId = $this->taskImportHelper->getKey([
'name' => $record['task'],
'project_id' => $projectId,

View File

@@ -92,7 +92,6 @@ class HarvestTimeEntriesImporter extends DefaultImporter
}
$taskId = null;
if ($record['Task'] !== '') {
$this->checkTaskNameLength($record['Task']);
$taskId = $this->taskImportHelper->getKey([
'name' => $record['Task'],
'project_id' => $projectId,

View File

@@ -199,7 +199,6 @@ 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,

View File

@@ -153,16 +153,9 @@ 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' => $memberId,
'member_id' => $this->memberImportHelper->getKeyByExternalIdentifier($userId),
], [
'user_id' => $userId,
'billable_rate' => $projectMember->rate !== null ? (int) ($projectMember->rate * 100) : null,
@@ -189,7 +182,6 @@ 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,

View File

@@ -97,7 +97,6 @@ class TogglTimeEntriesImporter extends DefaultImporter
}
$taskId = null;
if ($record['Task'] !== '') {
$this->checkTaskNameLength($record['Task']);
$taskId = $this->taskImportHelper->getKey([
'name' => $record['Task'],
'project_id' => $projectId,

View File

@@ -1,4 +0,0 @@
"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","",""
1 Project Client Status Visibility Tasks Tracked (h) Estimated (h) Remaining (h) Overage (h) Progress(%) Project members Project manager Note
2 Project for Big Company Big Company Active Public Task 1, Task 2, Task 3 1.38 Constantin Graf
3 Project without Client Active Public 0.00 Constantin Graf
4 TEST Big Company Active Public 0.00 Constantin Graf

View File

@@ -119,24 +119,6 @@ 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

View File

@@ -66,27 +66,4 @@ 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();
}
}