mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-19 13:42:14 +01:00
Compare commits
2 Commits
feature/ex
...
25f30fa820
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25f30fa820 | ||
|
|
37a8f43b23 |
@@ -1,32 +0,0 @@
|
|||||||
.git
|
|
||||||
.gitmodules
|
|
||||||
.github
|
|
||||||
.DS_Store
|
|
||||||
.fleet
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
*.log
|
|
||||||
npm-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
|
|
||||||
.phpunit.cache
|
|
||||||
.phpunit.result.cache
|
|
||||||
coverage
|
|
||||||
test-results
|
|
||||||
playwright-report
|
|
||||||
blob-report
|
|
||||||
playwright/.cache
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
extensions/*/node_modules
|
|
||||||
|
|
||||||
Homestead.json
|
|
||||||
Homestead.yaml
|
|
||||||
auth.json
|
|
||||||
.env.backup
|
|
||||||
.rnd
|
|
||||||
|
|
||||||
_ide_helper.php
|
|
||||||
.phpstorm.meta.php
|
|
||||||
|
|
||||||
storage/logs/*
|
|
||||||
12
.github/workflows/build-onpremise.yml
vendored
12
.github/workflows/build-onpremise.yml
vendored
@@ -8,7 +8,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/build-onpremise.yml'
|
- '.github/workflows/build-onpremise.yml'
|
||||||
- 'extensions/manifest.json'
|
|
||||||
- 'docker/prod/**'
|
- 'docker/prod/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@@ -96,19 +95,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: '20.x'
|
||||||
|
|
||||||
- name: "Read extension manifest"
|
|
||||||
id: extension-manifest
|
|
||||||
run: |
|
|
||||||
{
|
|
||||||
echo "invoicing_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
|
|
||||||
echo "invoicing_ref=$(jq -r '.Invoicing.ref' extensions/manifest.json)"
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: "Checkout invoicing extension"
|
- name: "Checkout invoicing extension"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
repository: ${{ steps.extension-manifest.outputs.invoicing_repository }}
|
repository: solidtime-io/extension-invoicing
|
||||||
ref: ${{ steps.extension-manifest.outputs.invoicing_ref }}
|
|
||||||
path: extensions/Invoicing
|
path: extensions/Invoicing
|
||||||
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}
|
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}
|
||||||
|
|
||||||
|
|||||||
22
.github/workflows/build-private.yml
vendored
22
.github/workflows/build-private.yml
vendored
@@ -8,7 +8,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/build-private.yml'
|
- '.github/workflows/build-private.yml'
|
||||||
- 'extensions/manifest.json'
|
|
||||||
- 'docker/prod/**'
|
- 'docker/prod/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
permissions:
|
permissions:
|
||||||
@@ -73,23 +72,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: '20.x'
|
||||||
|
|
||||||
- name: "Read extension manifest"
|
|
||||||
id: extension-manifest
|
|
||||||
run: |
|
|
||||||
{
|
|
||||||
echo "billing_repository=$(jq -r '.Billing.repository' extensions/manifest.json)"
|
|
||||||
echo "billing_ref=$(jq -r '.Billing.ref' extensions/manifest.json)"
|
|
||||||
echo "services_repository=$(jq -r '.Services.repository' extensions/manifest.json)"
|
|
||||||
echo "services_ref=$(jq -r '.Services.ref' extensions/manifest.json)"
|
|
||||||
echo "invoicing_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
|
|
||||||
echo "invoicing_ref=$(jq -r '.Invoicing.ref' extensions/manifest.json)"
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: "Checkout billing extension"
|
- name: "Checkout billing extension"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
repository: ${{ steps.extension-manifest.outputs.billing_repository }}
|
repository: solidtime-io/extension-billing
|
||||||
ref: ${{ steps.extension-manifest.outputs.billing_ref }}
|
|
||||||
path: extensions/Billing
|
path: extensions/Billing
|
||||||
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_BILLING_EXTENSION }}
|
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_BILLING_EXTENSION }}
|
||||||
|
|
||||||
@@ -109,8 +95,7 @@ jobs:
|
|||||||
- name: "Checkout services extension"
|
- name: "Checkout services extension"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
repository: ${{ steps.extension-manifest.outputs.services_repository }}
|
repository: solidtime-io/extension-services
|
||||||
ref: ${{ steps.extension-manifest.outputs.services_ref }}
|
|
||||||
path: extensions/Services
|
path: extensions/Services
|
||||||
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_SERVICES_EXTENSION }}
|
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_SERVICES_EXTENSION }}
|
||||||
|
|
||||||
@@ -128,8 +113,7 @@ jobs:
|
|||||||
- name: "Checkout invoicing extension"
|
- name: "Checkout invoicing extension"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
repository: ${{ steps.extension-manifest.outputs.invoicing_repository }}
|
repository: solidtime-io/extension-invoicing
|
||||||
ref: ${{ steps.extension-manifest.outputs.invoicing_ref }}
|
|
||||||
path: extensions/Invoicing
|
path: extensions/Invoicing
|
||||||
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}
|
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}
|
||||||
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -26,10 +26,9 @@ yarn-error.log
|
|||||||
/blob-report/
|
/blob-report/
|
||||||
/playwright/.cache/
|
/playwright/.cache/
|
||||||
/coverage
|
/coverage
|
||||||
/extensions/*
|
/extensions
|
||||||
!/extensions/.gitkeep
|
!/extensions/.gitkeep
|
||||||
!/extensions/extensions_autoload.php
|
!/extensions/extensions_autoload.php
|
||||||
!/extensions/manifest.json
|
|
||||||
/auth.json
|
/auth.json
|
||||||
/modules_statuses.json
|
/modules_statuses.json
|
||||||
/k8s
|
/k8s
|
||||||
|
|||||||
@@ -116,10 +116,12 @@ class ClockifyTimeEntriesImporter extends DefaultImporter
|
|||||||
throw new ImportException('Time entry description is too long');
|
throw new ImportException('Time entry description is too long');
|
||||||
}
|
}
|
||||||
$timeEntry->description = $record['Description'];
|
$timeEntry->description = $record['Description'];
|
||||||
|
if (isset($record['Billable'])) {
|
||||||
if (! in_array($record['Billable'], ['Yes', 'No'], true)) {
|
if (! in_array($record['Billable'], ['Yes', 'No'], true)) {
|
||||||
throw new ImportException('Invalid billable value');
|
throw new ImportException('Invalid billable value');
|
||||||
}
|
}
|
||||||
$timeEntry->billable = $record['Billable'] === 'Yes';
|
$timeEntry->billable = $record['Billable'] === 'Yes';
|
||||||
|
}
|
||||||
$timeEntry->tags = $this->getTags($record['Tags']);
|
$timeEntry->tags = $this->getTags($record['Tags']);
|
||||||
$timeEntry->is_imported = true;
|
$timeEntry->is_imported = true;
|
||||||
|
|
||||||
@@ -219,7 +221,6 @@ class ClockifyTimeEntriesImporter extends DefaultImporter
|
|||||||
'Group',
|
'Group',
|
||||||
'Email',
|
'Email',
|
||||||
'Tags',
|
'Tags',
|
||||||
'Billable',
|
|
||||||
'Start Date',
|
'Start Date',
|
||||||
'Start Time',
|
'Start Time',
|
||||||
'End Date',
|
'End Date',
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"Billing": {
|
|
||||||
"repository": "solidtime-io/extension-billing",
|
|
||||||
"ref": "v0.0.1"
|
|
||||||
},
|
|
||||||
"Services": {
|
|
||||||
"repository": "solidtime-io/extension-services",
|
|
||||||
"ref": "v0.0.1"
|
|
||||||
},
|
|
||||||
"Invoicing": {
|
|
||||||
"repository": "solidtime-io/extension-invoicing",
|
|
||||||
"ref": "v0.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -199,7 +199,7 @@ body {
|
|||||||
--muted-foreground: var(--color-text-tertiary);
|
--muted-foreground: var(--color-text-tertiary);
|
||||||
--accent: var(--color-bg-tertiary);
|
--accent: var(--color-bg-tertiary);
|
||||||
--accent-foreground: var(--color-text-primary);
|
--accent-foreground: var(--color-text-primary);
|
||||||
--destructive: 0 62.8% 30.6%;
|
--destructive: 0 72% 60%;
|
||||||
--destructive-foreground: var(--color-text-primary);
|
--destructive-foreground: var(--color-text-primary);
|
||||||
--border: var(--color-border-primary);
|
--border: var(--color-border-primary);
|
||||||
--input: var(--color-border-tertiary);
|
--input: var(--color-border-tertiary);
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"Project","Client","Description","Task","User","Group","Email","Tags","Start Date","Start Time","End Date","End Time","Duration (h)","Duration (decimal)","Billable Rate (USD)","Billable Amount (USD)"
|
||||||
|
"Project without Client","","","","Peter Tester","","peter.test@email.test","Development, Backend","03/04/2024","10:23:52 AM","03/04/2024","10:23:52 AM","00:00:00","0.00","0.00","0.00"
|
||||||
|
"Project for Big Company","Big Company","Working hard","Task 1","Peter Tester","","peter.test@email.test","","03/04/2024","10:23 AM","03/04/2024","11:23:01 AM","01:00:01","0.00","0.00","0.00"
|
||||||
|
@@ -41,6 +41,30 @@ class ClockifyTimeEntriesImporterTest extends ImporterTestAbstract
|
|||||||
$this->assertSame(1, $report->clientsCreated);
|
$this->assertSame(1, $report->clientsCreated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_import_of_test_file_without_billable_works_and_defaults_to_non_billable(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$organization = Organization::factory()->create();
|
||||||
|
$timezone = 'Europe/Vienna';
|
||||||
|
$importer = new ClockifyTimeEntriesImporter;
|
||||||
|
$importer->init($organization);
|
||||||
|
$data = Storage::disk('testfiles')->get('clockify_time_entries_import_test_4.csv');
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$importer->importData($data, $timezone);
|
||||||
|
$report = $importer->getReport();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$testScenario = $this->checkTestScenarioAfterImportExcludingTimeEntries(false, true);
|
||||||
|
$this->checkTimeEntries($testScenario, false, true);
|
||||||
|
$this->assertSame(2, $report->timeEntriesCreated);
|
||||||
|
$this->assertSame(2, $report->tagsCreated);
|
||||||
|
$this->assertSame(1, $report->tasksCreated);
|
||||||
|
$this->assertSame(1, $report->usersCreated);
|
||||||
|
$this->assertSame(2, $report->projectsCreated);
|
||||||
|
$this->assertSame(1, $report->clientsCreated);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_import_of_test_with_special_characters_description_succeeds(): void
|
public function test_import_of_test_with_special_characters_description_succeeds(): void
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class ImporterTestAbstract extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @return object{user1: User, project1: Project, project2: Project, tag1: Tag, tag2: Tag}
|
* @return object{user1: User, project1: Project, project2: Project, tag1: Tag, tag2: Tag}
|
||||||
*/
|
*/
|
||||||
protected function checkTestScenarioAfterImportExcludingTimeEntries(bool $detailed = false): object
|
protected function checkTestScenarioAfterImportExcludingTimeEntries(bool $detailed = false, bool $billableDefault = false): object
|
||||||
{
|
{
|
||||||
$users = User::all();
|
$users = User::all();
|
||||||
$this->assertCount(2, $users);
|
$this->assertCount(2, $users);
|
||||||
@@ -80,12 +80,12 @@ class ImporterTestAbstract extends TestCase
|
|||||||
$this->assertSame('#ef5350', $project1->color);
|
$this->assertSame('#ef5350', $project1->color);
|
||||||
$this->assertSame(null, $project1->billable_rate);
|
$this->assertSame(null, $project1->billable_rate);
|
||||||
// Project for Big Company
|
// Project for Big Company
|
||||||
$this->assertSame(true, $project2->is_billable);
|
$this->assertSame(! $billableDefault, $project2->is_billable);
|
||||||
$this->assertSame(false, $project2->is_public);
|
$this->assertSame(false, $project2->is_public);
|
||||||
$this->assertSame('#ec407a', $project2->color);
|
$this->assertSame('#ec407a', $project2->color);
|
||||||
$this->assertSame(10001, $project2->billable_rate);
|
$this->assertSame(10001, $project2->billable_rate);
|
||||||
// Project (Archived)
|
// Project (Archived)
|
||||||
$this->assertSame(true, $project3->is_billable);
|
$this->assertSame(! $billableDefault, $project3->is_billable);
|
||||||
$this->assertSame(true, $project3->is_public);
|
$this->assertSame(true, $project3->is_public);
|
||||||
$this->assertSame('#6a407f', $project3->color);
|
$this->assertSame('#6a407f', $project3->color);
|
||||||
$this->assertSame(null, $project3->billable_rate);
|
$this->assertSame(null, $project3->billable_rate);
|
||||||
@@ -176,7 +176,7 @@ class ImporterTestAbstract extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @param object{user1: User, project1: Project, project2: Project, tag1: Tag, tag2: Tag} $testScenario
|
* @param object{user1: User, project1: Project, project2: Project, tag1: Tag, tag2: Tag} $testScenario
|
||||||
*/
|
*/
|
||||||
protected function checkTimeEntries(object $testScenario, bool $secondRun = false): void
|
protected function checkTimeEntries(object $testScenario, bool $secondRun = false, bool $billableDefault = false): void
|
||||||
{
|
{
|
||||||
$timeEntries = TimeEntry::all();
|
$timeEntries = TimeEntry::all();
|
||||||
if ($secondRun) {
|
if ($secondRun) {
|
||||||
@@ -197,7 +197,7 @@ class ImporterTestAbstract extends TestCase
|
|||||||
$this->assertSame('Working hard', $timeEntry2->description);
|
$this->assertSame('Working hard', $timeEntry2->description);
|
||||||
$this->assertSame('2024-03-04 09:23:00', $timeEntry2->start->toDateTimeString());
|
$this->assertSame('2024-03-04 09:23:00', $timeEntry2->start->toDateTimeString());
|
||||||
$this->assertSame('2024-03-04 10:23:01', $timeEntry2->end->toDateTimeString());
|
$this->assertSame('2024-03-04 10:23:01', $timeEntry2->end->toDateTimeString());
|
||||||
$this->assertTrue($timeEntry2->billable);
|
$this->assertSame(! $billableDefault, $timeEntry2->billable);
|
||||||
$this->assertTrue($timeEntry2->is_imported);
|
$this->assertTrue($timeEntry2->is_imported);
|
||||||
$this->assertSame([], $timeEntry2->tags);
|
$this->assertSame([], $timeEntry2->tags);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user