Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added hourly and money budgets to activity, project and customer #843

Merged
merged 41 commits into from Jun 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
2523287
import budgets from v1
kevinpapst Jun 5, 2019
3791b81
php docs
kevinpapst Jun 5, 2019
500bd95
updated API docs config
kevinpapst Jun 5, 2019
0889874
added budget and time_budget fields to customer, project and activity
kevinpapst Jun 5, 2019
eb6168f
respect rate visibility permissions on dashboard
kevinpapst Jun 5, 2019
f26114e
Merge branch 'master' into budgets
kevinpapst Jun 7, 2019
2669a6a
Merge branch 'master' into budgets
kevinpapst Jun 7, 2019
5ed4507
added additional travis check for composer
kevinpapst Jun 8, 2019
1b948f9
fix funding
kevinpapst Jun 8, 2019
4b0db91
fix group by
kevinpapst Jun 9, 2019
370e6ed
updated statistic models
kevinpapst Jun 9, 2019
e8c6d69
phpdoc
kevinpapst Jun 9, 2019
ba653e9
removed unused message
kevinpapst Jun 9, 2019
1f98edc
new progressbar macro
kevinpapst Jun 9, 2019
8f816ea
simplified delete translations
kevinpapst Jun 9, 2019
b049e29
mark integration tests
kevinpapst Jun 9, 2019
5cee5f1
fixed integration group and wrongly extended KernelTestCase
kevinpapst Jun 9, 2019
30ca349
new budget permission
kevinpapst Jun 9, 2019
552c16c
removed budget column from project index screen
kevinpapst Jun 9, 2019
172a01e
new budget screens
kevinpapst Jun 9, 2019
5c78e84
links for new budget screen
kevinpapst Jun 9, 2019
381edd4
upgraded test database
kevinpapst Jun 9, 2019
ede73f9
set time and money budget in fixtures
kevinpapst Jun 9, 2019
8bb3358
include budget fields only when requested
kevinpapst Jun 10, 2019
780f2cd
updated icons
kevinpapst Jun 10, 2019
0babe87
new budget fields in API
kevinpapst Jun 10, 2019
742be61
fixed version
kevinpapst Jun 10, 2019
4a6e9d7
new permissions
kevinpapst Jun 10, 2019
b20dee9
code styles
kevinpapst Jun 10, 2019
231ceb8
fix user avatar icon in navbar
kevinpapst Jun 10, 2019
d7cf8f7
re-added files
kevinpapst Jun 10, 2019
0a5dbb2
fix tests
kevinpapst Jun 10, 2019
686196c
added tests
kevinpapst Jun 10, 2019
7aa0792
tests
kevinpapst Jun 10, 2019
ea4a195
do not change method signature when overwriting
kevinpapst Jun 10, 2019
d34a501
fixed duration formatter and added tests
kevinpapst Jun 10, 2019
910cbbc
fix phpdoc
kevinpapst Jun 10, 2019
7e1ff69
removed unused methods
kevinpapst Jun 10, 2019
a651495
prevent duplicate username and email in fixture
kevinpapst Jun 10, 2019
1d37534
Merge branch 'master' into budgets
kevinpapst Jun 10, 2019
f9a9f3e
fixed progressbar for percents above 1000
kevinpapst Jun 11, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
@@ -1,2 +1,2 @@
github: [kevinpapst]
#github: [kevinpapst]
custom: https://www.kimai.org/donate/
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -33,6 +33,7 @@ install:
- composer require zendframework/zend-ldap

script:
- composer validate --no-check-all --strict
- composer kimai:codestyle
- composer kimai:phpstan
- if [[ $CODECOVERAGE == 1 ]]; then vendor/bin/phpunit tests/ --coverage-clover=coverage.xml; else vendor/bin/phpunit tests/; fi;
Expand Down
7 changes: 5 additions & 2 deletions UPGRADING.md
Expand Up @@ -23,15 +23,18 @@ otherwise you can't use the new features:
- `delete_tag` - delete tags
- `edit_exported_timesheet` - allows to edit records which were exported
- `role_permissions` - view calculated permissions for user roles
- `budget_activity` - view and edit budgets for activities
- `budget_project` - view and edit budgets for projects
- `budget_customer` - view and edit budgets for customers

Removed permission:
- `system_actions` - removed experimental feature to flush app cache from the about screen

### BC BREAKS

- API: Format for queries including a datetime object fixed, finally using the HTML5 format (previously `2019-03-02 14:23` - now `2019-03-02T14:23:00`)
- API: Format for queries including a datetime object fixed to use HTML5 format (previously `2019-03-02 14:23` - now `2019-03-02T14:23:00`)
- **Permission config**: the `permissions` definition in your `local.yaml` needs to be verified/changed, as the internal structure was highly optimized to simplify the definition.
Thanks to the new structure, you should be able to remove almost everything from your `local.yaml`: please read [the updated permission docu](https://www.kimai.org/documentation/permissions.html).
Thanks to the new structure, you should be able to remove almost everything from your `local.yaml` (tip: start over from scratch!). Please read [the updated permission docu](https://www.kimai.org/documentation/permissions.html).

## [0.9](https://github.com/kevinpapst/kimai2/releases/tag/0.9)

Expand Down
2 changes: 1 addition & 1 deletion assets/sass/navbar.scss
Expand Up @@ -7,7 +7,7 @@

.navbar-nav {
li>a.ddt-large {
padding: 16px 12px 11px 12px;
padding: 15px 12px 11px 10px;
font-size: 10px;
}
li.messages-menu ul.menu li {
Expand Down
10 changes: 5 additions & 5 deletions config/packages/kimai.yaml
Expand Up @@ -77,9 +77,9 @@ kimai:
permissions:
# mapping complex rule sets of single permissions to named "sets" ("set name" = [array of "permissions and sets"])
sets:
ACTIVITIES: ['view_activity','create_activity','edit_activity','delete_activity']
PROJECTS: ['view_project','create_project','edit_project','delete_project']
CUSTOMERS: ['view_customer','create_customer','edit_customer','delete_customer']
ACTIVITIES: ['view_activity','create_activity','edit_activity','budget_activity','delete_activity']
PROJECTS: ['view_project','create_project','edit_project','budget_project','delete_project']
CUSTOMERS: ['view_customer','create_customer','edit_customer','budget_customer','delete_customer']
INVOICE: ['view_invoice','create_invoice']
INVOICE_TEMPLATE: ['view_invoice_template','create_invoice_template','edit_invoice_template','delete_invoice_template']
TIMESHEET: ['view_own_timesheet','start_own_timesheet','stop_own_timesheet','create_own_timesheet','edit_own_timesheet','export_own_timesheet','delete_own_timesheet']
Expand Down Expand Up @@ -173,7 +173,7 @@ kimai:
user_rates:
title: ~
order: 20
permission: ROLE_USER
permission: view_rate_own_timesheet
widgets: [userAmountToday, userAmountWeek, userAmountMonth, userAmountYear]
duration:
title: dashboard.all
Expand All @@ -188,7 +188,7 @@ kimai:
rates:
title: ~
order: 50
permission: ROLE_ADMIN
permission: view_rate_other_timesheet
widgets: [amountToday, amountWeek, amountMonth, amountYear]

widgets:
Expand Down
22 changes: 8 additions & 14 deletions config/packages/nelmio_api_doc.yaml
Expand Up @@ -22,29 +22,23 @@ nelmio_api_doc:
path_patterns:
- ^/api(?!/doc)
documentation:
# host: '{{hostname}}'
schemes: [http, https]
#host: '{{hostname}}'
host: '%router.request_context.host%'
basePath: '%router.request_context.base_url%'
schemes: ['%router.request_context.scheme%']
info:
title: Kimai 2 - API Docs
description: |
REST API for the Kimai 2 time-tracking software. It is not yet considered stable and BC breaks might happen, even though I try to avoid them as much as possible.
- Collections return less data than explicit entity calls
- DateTime formats are explained in detail at https://www.kimai.org/documentation/rest-api.html
REST API for the Kimai 2 time-tracking software. Read more about its usage in the [API documentation](https://www.kimai.org/documentation/rest-api.html) and then download a [Swagger file](doc.json) for import e.g. in Postman.
Be aware: it is not yet considered stable and BC breaks might happen, but we try to avoid them.
version: 0.3
# parameters:
# hostname:
# name: hostname
# in: url
# description: the hostname where your api runs
# required: true
# type: string
securityDefinitions:
X-AUTH-USER:
apiUser:
type: apiKey
description: 'Value: {Username}'
name: X-AUTH-USER
in: header
X-AUTH-TOKEN:
apiToken:
type: apiKey
description: 'Value: {API Token}'
name: X-AUTH-TOKEN
Expand Down
8 changes: 7 additions & 1 deletion config/serializer/App/Entity.Activity.yml
@@ -1,6 +1,6 @@
App\Entity\Activity:
exclusion_policy: All
custom_accessor_order: [id, name, comment, visible, project, fixedRate, hourlyRate, color]
custom_accessor_order: [id, name, comment, visible, project, fixedRate, hourlyRate, color, budget, timeBudget]
properties:
id:
include: true
Expand All @@ -14,6 +14,12 @@ App\Entity\Activity:
visible:
include: true
groups: [Default]
budget:
include: true
groups: [Entity]
timeBudget:
include: true
groups: [Entity]
fixedRate:
include: true
groups: [Activity]
Expand Down
8 changes: 7 additions & 1 deletion config/serializer/App/Entity.Customer.yml
@@ -1,6 +1,6 @@
App\Entity\Customer:
exclusion_policy: All
custom_accessor_order: [id, name, number, comment, visible, company, contact, address, country, currency, phone, fax, mobile, email, homepage, timezone, fixedRate, hourlyRate, color]
custom_accessor_order: [id, name, number, comment, visible, company, contact, address, country, currency, phone, fax, mobile, email, homepage, timezone, fixedRate, hourlyRate, color, budget, timeBudget]
properties:
id:
include: true
Expand All @@ -14,6 +14,12 @@ App\Entity\Customer:
groups: [Entity]
visible:
include: true
budget:
include: true
groups: [Entity]
timeBudget:
include: true
groups: [Entity]
company:
include: true
groups: [Entity]
Expand Down
5 changes: 4 additions & 1 deletion config/serializer/App/Entity.Project.yml
@@ -1,6 +1,6 @@
App\Entity\Project:
exclusion_policy: All
custom_accessor_order: [id, name, comment, visible, budget, orderNumber, customer, fixedRate, hourlyRate, color]
custom_accessor_order: [id, name, comment, visible, orderNumber, customer, fixedRate, hourlyRate, color, budget, timeBudget]
properties:
id:
include: true
Expand All @@ -14,6 +14,9 @@ App\Entity\Project:
budget:
include: true
groups: [Entity]
timeBudget:
include: true
groups: [Entity]
orderNumber:
include: true
groups: [Entity]
Expand Down

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions public/build/entrypoints.json
Expand Up @@ -8,7 +8,7 @@
"build/app.26c26669.js"
],
"css": [
"build/app.16fefccc.css"
"build/app.7f4a18a1.css"
]
},
"chart": {
Expand Down Expand Up @@ -36,7 +36,7 @@
"build/0.66b5fd0b.js": "sha384-ncT/BKhCsqH6jhxwdsSG95m1ei7ZZjeZtzH1262h+OPUU80TSFFE3dt+abcHHMok",
"build/1.93f0cf2b.js": "sha384-pmnwzvj+UJhDD3uDf+ekLARMBRtMDxWGbnJDrJvwIoRZd3MW/tOGzAW5Ybhbvw20",
"build/app.26c26669.js": "sha384-SyN1k+3kOWKnJSOyY+atWLSXNubTbsgz1DZ47jH8PrgLFj9WjXB9GRhO6E7tpJWf",
"build/app.16fefccc.css": "sha384-eJfoYmxOaglIQAsTI8AEaGdyRU/Moe/ikO3V4ELZFjhd2i7K3aiq6Y5mpDqXQljX",
"build/app.7f4a18a1.css": "sha384-p8Dw7CP1RxxJ2K5yuaNpCw8r1lKd64DlVA2IQeEGxBAC2QxOjweafd8w9CSMk0GC",
"build/2.c06cd055.js": "sha384-txR0QG+838LKYtPQ99Gx4OU7WmgN9J3joZEyGwIskSz74EN1T4/IBVnmNaKiFN1q",
"build/chart.2bb71e2e.js": "sha384-I57c9DtU3AOG2kzKqIZkIu0hi1aGYHRZ5QG4LKC9+9slzJnAMttPGXoL2cQG3m6y",
"build/calendar.59417f4c.js": "sha384-16sOZQy1UmOaoLAVFPfHnF8nFqUxhc4URAg+ypJnnab8uqZAGHDfFFrnq0/6PXl1",
Expand Down
2 changes: 1 addition & 1 deletion public/build/manifest.json
Expand Up @@ -2,7 +2,7 @@
"build/0.66b5fd0b.js": "build/0.66b5fd0b.js",
"build/1.93f0cf2b.js": "build/1.93f0cf2b.js",
"build/2.c06cd055.js": "build/2.c06cd055.js",
"build/app.css": "build/app.16fefccc.css",
"build/app.css": "build/app.7f4a18a1.css",
"build/app.js": "build/app.26c26669.js",
"build/calendar.css": "build/calendar.b0551848.css",
"build/calendar.js": "build/calendar.59417f4c.js",
Expand Down
6 changes: 4 additions & 2 deletions src/Command/KimaiImporterCommand.php
Expand Up @@ -645,7 +645,7 @@ protected function importCustomers(SymfonyStyle $io, $customers, $country, $curr
* ["visible"]=> string(1) "1"
* --- ["filter"]=> string(1) "0"
* ["trash"]=> string(1) "1"
* --- ["budget"]=> string(4) "0.00"
* ["budget"]=> string(4) "0.00"
* --- ["effort"]=> NULL
* --- ["approved"]=> NULL
* --- ["internal"]=> string(1) "0"
Expand Down Expand Up @@ -677,6 +677,7 @@ protected function importProjects(SymfonyStyle $io, $projects, array $fixedRates
->setName($name)
->setComment($oldProject['comment'] ?: null)
->setVisible($isActive)
->setBudget($oldProject['budget'] ?: 0)
;

foreach ($fixedRates as $fixedRow) {
Expand Down Expand Up @@ -733,7 +734,7 @@ protected function importProjects(SymfonyStyle $io, $projects, array $fixedRates
* $activityToProject
* ["projectID"]=> string(1) "1"
* ["activityID"]=> string(1) "1"
* -- ["budget"]=> string(4) "0.00"
* ["budget"]=> string(4) "0.00"
* -- ["effort"]=> string(4) "0.00"
* -- ["approved"]=> string(4) "0.00"
*
Expand Down Expand Up @@ -831,6 +832,7 @@ protected function createActivity(
->setName($name)
->setComment($oldActivity['comment'] ?: null)
->setVisible($isActive)
->setBudget($oldActivity['budget'] ?: 0)
;

if (null !== $projectId) {
Expand Down
16 changes: 16 additions & 0 deletions src/Controller/ActivityController.php
Expand Up @@ -100,6 +100,21 @@ public function createAction(Request $request, ?Project $project = null)
return $this->renderActivityForm($activity, $request);
}

/**
* @Route(path="/{id}/budget", name="admin_activity_budget", methods={"GET"})
* @Security("is_granted('budget', activity)")
*
* @param Activity $activity
* @return \Symfony\Component\HttpFoundation\Response
*/
public function budgetAction(Activity $activity)
{
return $this->render('activity/budget.html.twig', [
'activity' => $activity,
'stats' => $this->getRepository()->getActivityStatistics($activity)
]);
}

/**
* @Route(path="/{id}/edit", name="admin_activity_edit", methods={"GET", "POST"})
* @Security("is_granted('edit', activity)")
Expand Down Expand Up @@ -244,6 +259,7 @@ private function createEditForm(Activity $activity)
'method' => 'POST',
'create_more' => true,
'customer' => true,
'include_budget' => $this->isGranted('budget', $activity)
]);
}
}
18 changes: 17 additions & 1 deletion src/Controller/CustomerController.php
Expand Up @@ -109,6 +109,21 @@ public function createAction(Request $request)
return $this->renderCustomerForm($customer, $request);
}

/**
* @Route(path="/{id}/budget", name="admin_customer_budget", methods={"GET"})
* @Security("is_granted('budget', customer)")
*
* @param Customer $customer
* @return \Symfony\Component\HttpFoundation\Response
*/
public function budgetAction(Customer $customer)
{
return $this->render('customer/budget.html.twig', [
'customer' => $customer,
'stats' => $this->getRepository()->getCustomerStatistics($customer)
]);
}

/**
* @Route(path="/{id}/edit", name="admin_customer_edit", methods={"GET", "POST"})
* @Security("is_granted('edit', customer)")
Expand Down Expand Up @@ -232,7 +247,8 @@ private function createEditForm(Customer $customer)

return $this->createForm(CustomerEditForm::class, $customer, [
'action' => $url,
'method' => 'POST'
'method' => 'POST',
'include_budget' => $this->isGranted('budget', $customer)
]);
}
}
16 changes: 16 additions & 0 deletions src/Controller/ProjectController.php
Expand Up @@ -101,6 +101,21 @@ public function createAction(Request $request, ?Customer $customer = null)
return $this->renderProjectForm($project, $request);
}

/**
* @Route(path="/{id}/budget", name="admin_project_budget", methods={"GET"})
* @Security("is_granted('budget', project)")
*
* @param Project $project
* @return \Symfony\Component\HttpFoundation\Response
*/
public function budgetAction(Project $project)
{
return $this->render('project/budget.html.twig', [
'project' => $project,
'stats' => $this->getRepository()->getProjectStatistics($project)
]);
}

/**
* @Route(path="/{id}/edit", name="admin_project_edit", methods={"GET", "POST"})
* @Security("is_granted('edit', project)")
Expand Down Expand Up @@ -238,6 +253,7 @@ private function createEditForm(Project $project)
'method' => 'POST',
'currency' => $currency,
'create_more' => true,
'include_budget' => $this->isGranted('budget', $project)
]);
}
}
27 changes: 26 additions & 1 deletion src/DataFixtures/CustomerFixtures.php
Expand Up @@ -32,6 +32,8 @@ class CustomerFixtures extends Fixture
public const MAX_CUSTOMERS = 15;
public const MIN_BUDGET = 0;
public const MAX_BUDGET = 100000;
public const MIN_TIME_BUDGET = 0;
public const MAX_TIME_BUDGET = 10000000;
public const MIN_GLOBAL_ACTIVITIES = 5;
public const MAX_GLOBAL_ACTIVITIES = 30;
public const MIN_PROJECTS_PER_CUSTOMER = 2;
Expand Down Expand Up @@ -100,6 +102,14 @@ private function createCustomer(Generator $faker, $visible)
->setVisible($visible)
;

if (rand(0, 3) % 3) {
$entry->setBudget(rand(self::MIN_BUDGET, self::MAX_BUDGET));
}

if (rand(0, 3) % 3) {
$entry->setTimeBudget(rand(self::MIN_TIME_BUDGET, self::MAX_TIME_BUDGET));
}

return $entry;
}

Expand All @@ -115,12 +125,19 @@ private function createProject(Generator $faker, Customer $customer, $visible)

$entry
->setName($faker->catchPhrase . ($visible ? '' : ' (x)'))
->setBudget(rand(self::MIN_BUDGET, self::MAX_BUDGET))
->setComment($faker->text)
->setCustomer($customer)
->setVisible($visible)
;

if (rand(0, 3) % 3) {
$entry->setBudget(rand(self::MIN_BUDGET, self::MAX_BUDGET));
}

if (rand(0, 3) % 3) {
$entry->setTimeBudget(rand(self::MIN_TIME_BUDGET, self::MAX_TIME_BUDGET));
}

return $entry;
}

Expand All @@ -140,6 +157,14 @@ private function createActivity(Generator $faker, ?Project $project, $visible)
->setVisible($visible)
;

if (rand(0, 3) % 3) {
$entry->setBudget(rand(self::MIN_BUDGET, self::MAX_BUDGET));
}

if (rand(0, 3) % 3) {
$entry->setTimeBudget(rand(self::MIN_TIME_BUDGET, self::MAX_TIME_BUDGET));
}

return $entry;
}
}