@@ -394,6 +394,10 @@
|
||||
<source>admin_project.subtitle</source>
|
||||
<target>Ein Projekt fasst Tätigkeiten für jeweils einen Kunden in einer Gruppe zusammen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="admin_project.delete_confirm">
|
||||
<source>admin_project.delete_confirm</source>
|
||||
<target>Momentan existieren für das Projekt %project% des Kunden %customer% insgesamt %activities% Aktivitäten und %records% Zeiteinträge, welche sich auf eine Gesamtdauer von %duration% belaufen. Alle Aktivitäten und Zeiteinträge werden ebenfalls mit gelöscht!</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
Admin: Activity
|
||||
@@ -408,7 +412,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="admin_activity.delete_confirm">
|
||||
<source>admin_activity.delete_confirm</source>
|
||||
<target>Momentan existieren für die Aktivität %activity% im Projekt %project% für den Kunden %customer% insgesamt %count% Zeiteinträge, welche sich auf eine Gesamtdauer von %duration% belaufen. Alle Zeiteinträge werden ebenfalls mit gelöscht!</target>
|
||||
<target>Momentan existieren für die Aktivität %activity% im Projekt %project% für den Kunden %customer% insgesamt %records% Zeiteinträge, welche sich auf eine Gesamtdauer von %duration% belaufen. Alle Zeiteinträge werden ebenfalls mit gelöscht!</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -132,7 +132,7 @@ class DashboardController extends Controller
|
||||
'widgets' => [
|
||||
"{{ widgets.info_box_more('stats.userTotal', user.totalAmount, ' ', path('admin_user'), 'user') }}",
|
||||
"{{ widgets.info_box_more('stats.customerTotal', customer.totalAmount, '', path('admin_customer'), 'users', 'blue') }}",
|
||||
"{{ widgets.info_box_more('stats.projectsTotal', project.totalAmount, '', path('admin_project'), 'book', 'yellow') }}",
|
||||
"{{ widgets.info_box_more('stats.projectsTotal', project.count, '', path('admin_project'), 'book', 'yellow') }}",
|
||||
"{{ widgets.info_box_more('stats.activitiesTotal', activity.count, '', path('admin_activity'), 'tasks', 'purple') }}",
|
||||
],
|
||||
];
|
||||
|
||||
@@ -20,6 +20,7 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
use TimesheetBundle\Form\ProjectDeleteForm;
|
||||
use TimesheetBundle\Form\ProjectEditForm;
|
||||
use TimesheetBundle\Form\Toolbar\ProjectToolbarForm;
|
||||
use TimesheetBundle\Repository\Query\ProjectQuery;
|
||||
@@ -34,6 +35,15 @@ use TimesheetBundle\Repository\Query\ProjectQuery;
|
||||
*/
|
||||
class ProjectController extends AbstractController
|
||||
{
|
||||
|
||||
/**
|
||||
* @return \TimesheetBundle\Repository\ProjectRepository
|
||||
*/
|
||||
protected function getRepository()
|
||||
{
|
||||
return $this->getDoctrine()->getRepository(Project::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return ProjectQuery
|
||||
@@ -49,7 +59,7 @@ class ProjectController extends AbstractController
|
||||
$customer = !empty(trim($customer)) ? trim($customer) : null;
|
||||
|
||||
if ($customer !== null) {
|
||||
$repo = $this->getDoctrine()->getRepository(Customer::class);
|
||||
$repo = $this->getRepository();
|
||||
$customer = $repo->getById($customer);
|
||||
}
|
||||
|
||||
@@ -104,6 +114,45 @@ class ProjectController extends AbstractController
|
||||
return $this->renderProjectForm($project, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* The route to delete an existing entry.
|
||||
*
|
||||
* @Route("/{id}/delete", name="admin_project_delete")
|
||||
* @Method({"GET", "POST"})
|
||||
* @Security("is_granted('delete', project)")
|
||||
*
|
||||
* @param Project $project
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function deleteAction(Project $project, Request $request)
|
||||
{
|
||||
$stats = $this->getRepository()->getProjectStatistics($project);
|
||||
|
||||
$deleteForm = $this->createForm(ProjectDeleteForm::class, $project, [
|
||||
'action' => $this->generateUrl('admin_project_delete', ['id' => $project->getId()]),
|
||||
'method' => 'POST'
|
||||
]);
|
||||
|
||||
$deleteForm->handleRequest($request);
|
||||
|
||||
if ($stats->getRecordAmount() == 0 || ($deleteForm->isSubmitted() && $deleteForm->isValid())) {
|
||||
$entityManager = $this->getDoctrine()->getManager();
|
||||
$entityManager->remove($project);
|
||||
$entityManager->flush();
|
||||
|
||||
$this->flashSuccess('action.deleted_successfully');
|
||||
|
||||
return $this->redirectToRoute('admin_project', ['id' => $project->getId()]);
|
||||
}
|
||||
|
||||
return $this->render('TimesheetBundle:admin:project_delete.html.twig', [
|
||||
'project' => $project,
|
||||
'stats' => $stats,
|
||||
'form' => $deleteForm->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Project $project
|
||||
* @param Request $request
|
||||
@@ -125,13 +174,10 @@ class ProjectController extends AbstractController
|
||||
return $this->redirectToRoute('admin_project', ['id' => $project->getId()]);
|
||||
}
|
||||
|
||||
return $this->render(
|
||||
'TimesheetBundle:admin:project_edit.html.twig',
|
||||
[
|
||||
'project' => $project,
|
||||
'form' => $editForm->createView()
|
||||
]
|
||||
);
|
||||
return $this->render('TimesheetBundle:admin:project_edit.html.twig', [
|
||||
'project' => $project,
|
||||
'form' => $editForm->createView()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,16 +186,12 @@ class ProjectController extends AbstractController
|
||||
*/
|
||||
protected function getToolbarForm(ProjectQuery $query)
|
||||
{
|
||||
return $this->createForm(
|
||||
ProjectToolbarForm::class,
|
||||
$query,
|
||||
[
|
||||
'action' => $this->generateUrl('admin_project_paginated', [
|
||||
'page' => $query->getPage(),
|
||||
]),
|
||||
'method' => 'GET',
|
||||
]
|
||||
);
|
||||
return $this->createForm(ProjectToolbarForm::class, $query, [
|
||||
'action' => $this->generateUrl('admin_project_paginated', [
|
||||
'page' => $query->getPage(),
|
||||
]),
|
||||
'method' => 'GET',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
38
src/TimesheetBundle/Form/ProjectDeleteForm.php
Normal file
38
src/TimesheetBundle/Form/ProjectDeleteForm.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai package.
|
||||
*
|
||||
* (c) Kevin Papst <kevin@kevinpapst.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace TimesheetBundle\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use TimesheetBundle\Entity\Project;
|
||||
|
||||
/**
|
||||
* The form used to delete Projects.
|
||||
*
|
||||
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||
*/
|
||||
class ProjectDeleteForm extends AbstractType
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Project::class,
|
||||
'csrf_protection' => true,
|
||||
'csrf_field_name' => '_token',
|
||||
'csrf_token_id' => 'admin_project_delete',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -21,21 +21,95 @@ class ProjectStatistic
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $totalAmount = 0;
|
||||
protected $count = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $recordAmount = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $recordDuration = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $activityAmount = 0;
|
||||
|
||||
/**
|
||||
* Returns the total amount of included timesheet records.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRecordAmount()
|
||||
{
|
||||
return $this->recordAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $recordAmount
|
||||
* @return ProjectStatistic
|
||||
*/
|
||||
public function setRecordAmount($recordAmount)
|
||||
{
|
||||
$this->recordAmount = (int) $recordAmount;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total duration of all included timesheet records.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRecordDuration()
|
||||
{
|
||||
return $this->recordDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $recordDuration
|
||||
* @return ProjectStatistic
|
||||
*/
|
||||
public function setRecordDuration($recordDuration)
|
||||
{
|
||||
$this->recordDuration = (int) $recordDuration;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of activities that are included in the statistic result.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCount()
|
||||
{
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
* @return ProjectStatistic
|
||||
*/
|
||||
public function setCount($count)
|
||||
{
|
||||
$this->count = (int) $count;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalAmount()
|
||||
public function getActivityAmount()
|
||||
{
|
||||
return $this->totalAmount;
|
||||
return $this->activityAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $totalAmount
|
||||
* @param int $activityAmount
|
||||
* @return ProjectStatistic
|
||||
*/
|
||||
public function setTotalAmount($totalAmount)
|
||||
public function setActivityAmount($activityAmount)
|
||||
{
|
||||
$this->totalAmount = $totalAmount;
|
||||
$this->activityAmount = (int) $activityAmount;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace TimesheetBundle\Repository;
|
||||
|
||||
use AppBundle\Repository\AbstractRepository;
|
||||
use Doctrine\ORM\Query;
|
||||
use TimesheetBundle\Entity\Project;
|
||||
use TimesheetBundle\Model\ProjectStatistic;
|
||||
use TimesheetBundle\Repository\Query\ProjectQuery;
|
||||
@@ -46,7 +47,40 @@ class ProjectRepository extends AbstractRepository
|
||||
->getSingleScalarResult();
|
||||
|
||||
$stats = new ProjectStatistic();
|
||||
$stats->setTotalAmount($countAll);
|
||||
$stats->setCount($countAll);
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves statistics for one activity.
|
||||
*
|
||||
* @param Project $project
|
||||
* @return ProjectStatistic
|
||||
*/
|
||||
public function getProjectStatistics(Project $project)
|
||||
{
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
|
||||
$qb->select('COUNT(t.id) as recordAmount', 'SUM(t.duration) as recordDuration, COUNT(DISTINCT(a.id)) as activityAmount')
|
||||
->from('TimesheetBundle:Activity', 'a')
|
||||
->join('TimesheetBundle:Timesheet', 't')
|
||||
->where('a.project = :project')
|
||||
->andWhere('t.activity = a.id')
|
||||
;
|
||||
|
||||
$result = $qb->getQuery()->execute(['project' => $project], Query::HYDRATE_ARRAY);
|
||||
|
||||
$stats = new ProjectStatistic();
|
||||
|
||||
if (isset($result[0])) {
|
||||
$dbStats = $result[0];
|
||||
|
||||
$stats->setCount(1);
|
||||
$stats->setRecordAmount($dbStats['recordAmount']);
|
||||
$stats->setRecordDuration($dbStats['recordDuration']);
|
||||
$stats->setActivityAmount($dbStats['activityAmount']);
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
'%activity%': '<strong>' ~ activity.name ~ '</strong>',
|
||||
'%project%': '<strong>' ~ activity.project.name ~ '</strong>',
|
||||
'%customer%': '<strong>' ~ activity.project.customer.name ~ '</strong>',
|
||||
'%count%': '<strong>' ~ stats.recordAmount ~ '</strong>',
|
||||
'%records%': '<strong>' ~ stats.recordAmount ~ '</strong>',
|
||||
'%duration%': '<strong>' ~ stats.recordDuration|duration ~ '</strong>'
|
||||
} %}
|
||||
|
||||
|
||||
@@ -34,10 +34,14 @@
|
||||
<td class="hidden-xs">{{ entry.budget|money(entry.customer.currency) }}</td>
|
||||
<td>{{ widgets.label_visible(entry.visible) }}</td>
|
||||
<td>
|
||||
{{ widgets.button_group({
|
||||
'edit': path('admin_project_edit', {'id': entry.id}),
|
||||
'trash': '#'
|
||||
}) }}
|
||||
{% set actionButtons = {} %}
|
||||
{% if is_granted('edit', entry) %}
|
||||
{% set actionButtons = {'edit': path('admin_project_edit', {'id': entry.id})}|merge(actionButtons) %}
|
||||
{% endif %}
|
||||
{% if is_granted('delete', entry) %}
|
||||
{% set actionButtons = actionButtons|merge({'trash': path('admin_project_delete', {'id': entry.id})}) %}
|
||||
{% endif %}
|
||||
{{ widgets.button_group(actionButtons) }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "macros/datatables.html.twig" as tables %}
|
||||
|
||||
{% block page_title %}{{ 'admin_project.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'admin_project.subtitle'|trans }}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
{% set params = {
|
||||
'%project%': '<strong>' ~ project.name ~ '</strong>',
|
||||
'%customer%': '<strong>' ~ project.customer.name ~ '</strong>',
|
||||
'%records%': '<strong>' ~ stats.recordAmount ~ '</strong>',
|
||||
'%activities%': '<strong>' ~ stats.activityAmount ~ '</strong>',
|
||||
'%duration%': '<strong>' ~ stats.recordDuration|duration ~ '</strong>'
|
||||
} %}
|
||||
|
||||
{{ include('default/_form_delete.html.twig', {
|
||||
'message': "admin_project.delete_confirm"|trans(params)|raw,
|
||||
'form': form,
|
||||
'back': path('admin_project')
|
||||
}) }}
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user